Make krb5 over SMB2 identical to the way we handle it in SMB1.
[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 "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         struct smbd_server_connection *sconn = smbd_server_conn;
174
175         if (!spnego_parse_krb5_wrap(*secblob, &ticket, tok_id)) {
176                 status = NT_STATUS_LOGON_FAILURE;
177                 goto fail;
178         }
179
180         status = ads_verify_ticket(smb2req, lp_realm(), 0, &ticket,
181                                 &client, &logon_info, &ap_rep,
182                                 &session_key, true);
183
184         if (!NT_STATUS_IS_OK(status)) {
185                 DEBUG(1,("smb2: Failed to verify incoming ticket with error %s!\n",
186                         nt_errstr(status)));
187                 if (!NT_STATUS_EQUAL(status, NT_STATUS_TIME_DIFFERENCE_AT_DC)) {
188                         status = NT_STATUS_LOGON_FAILURE;
189                 }
190                 goto fail;
191         }
192
193         DEBUG(3,("smb2: Ticket name is [%s]\n", client));
194
195         p = strchr_m(client, '@');
196         if (!p) {
197                 DEBUG(3,("smb2: %s Doesn't look like a valid principal\n",
198                         client));
199                 status = NT_STATUS_LOGON_FAILURE;
200                 goto fail;
201         }
202
203         *p = 0;
204
205         /* save the PAC data if we have it */
206
207         if (logon_info) {
208                 netsamlogon_cache_store(client, &logon_info->info3);
209         }
210
211         if (!strequal(p+1, lp_realm())) {
212                 DEBUG(3,("smb2: Ticket for foreign realm %s@%s\n", client, p+1));
213                 if (!lp_allow_trusted_domains()) {
214                         status = NT_STATUS_LOGON_FAILURE;
215                         goto fail;
216                 }
217         }
218
219         /* this gives a fully qualified user name (ie. with full realm).
220            that leads to very long usernames, but what else can we do? */
221
222         domain = p+1;
223
224         if (logon_info && logon_info->info3.base.domain.string) {
225                 domain = talloc_strdup(talloc_tos(),
226                                         logon_info->info3.base.domain.string);
227                 if (!domain) {
228                         status = NT_STATUS_NO_MEMORY;
229                         goto fail;
230                 }
231                 DEBUG(10, ("smb2: Mapped to [%s] (using PAC)\n", domain));
232         } else {
233
234                 /* If we have winbind running, we can (and must) shorten the
235                    username by using the short netbios name. Otherwise we will
236                    have inconsistent user names. With Kerberos, we get the
237                    fully qualified realm, with ntlmssp we get the short
238                    name. And even w2k3 does use ntlmssp if you for example
239                    connect to an ip address. */
240
241                 wbcErr wbc_status;
242                 struct wbcDomainInfo *info = NULL;
243
244                 DEBUG(10, ("smb2: Mapping [%s] to short name\n", domain));
245
246                 wbc_status = wbcDomainInfo(domain, &info);
247
248                 if (WBC_ERROR_IS_OK(wbc_status)) {
249                         domain = talloc_strdup(talloc_tos(), info->short_name);
250
251                         wbcFreeMemory(info);
252                         if (!domain) {
253                                 status = NT_STATUS_NO_MEMORY;
254                                 goto fail;
255                         }
256                         DEBUG(10, ("smb2: Mapped to [%s] (using Winbind)\n", domain));
257                 } else {
258                         DEBUG(3, ("smb2: Could not find short name: %s\n",
259                                 wbcErrorString(wbc_status)));
260                 }
261         }
262
263         /* We have to use fstring for this - map_username requires it. */
264         fstr_sprintf(user, "%s%c%s", domain, *lp_winbind_separator(), client);
265
266         /* lookup the passwd struct, create a new user if necessary */
267
268         username_was_mapped = map_username(sconn, user);
269
270         pw = smb_getpwnam(talloc_tos(), user, real_username, true );
271         if (pw) {
272                 /* if a real user check pam account restrictions */
273                 /* only really perfomed if "obey pam restriction" is true */
274                 /* do this before an eventual mapping to guest occurs */
275                 status = smb_pam_accountcheck(pw->pw_name);
276                 if (!NT_STATUS_IS_OK(status)) {
277                         DEBUG(1,("smb2: PAM account restriction "
278                                 "prevents user login\n"));
279                         goto fail;
280                 }
281         }
282
283         if (!pw) {
284
285                 /* this was originally the behavior of Samba 2.2, if a user
286                    did not have a local uid but has been authenticated, then
287                    map them to a guest account */
288
289                 if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_UID){
290                         map_domainuser_to_guest = true;
291                         fstrcpy(user,lp_guestaccount());
292                         pw = smb_getpwnam(talloc_tos(), user, real_username, true );
293                 }
294
295                 /* extra sanity check that the guest account is valid */
296
297                 if (!pw) {
298                         DEBUG(1,("smb2: Username %s is invalid on this system\n",
299                                 user));
300                         status = NT_STATUS_LOGON_FAILURE;
301                         goto fail;
302                 }
303         }
304
305         /* setup the string used by %U */
306
307         sub_set_smb_name(real_username);
308         reload_services(true);
309
310         if (map_domainuser_to_guest) {
311                 make_server_info_guest(session, &session->server_info);
312         } else if (logon_info) {
313                 /* pass the unmapped username here since map_username()
314                    will be called again from inside make_server_info_info3() */
315
316                 status = make_server_info_info3(session,
317                                                 client,
318                                                 domain,
319                                                 &session->server_info,
320                                                 &logon_info->info3);
321                 if (!NT_STATUS_IS_OK(status) ) {
322                         DEBUG(1,("smb2: make_server_info_info3 failed: %s!\n",
323                                 nt_errstr(status)));
324                         goto fail;
325                 }
326
327         } else {
328                 /*
329                  * We didn't get a PAC, we have to make up the user
330                  * ourselves. Try to ask the pdb backend to provide
331                  * SID consistency with ntlmssp session setup
332                  */
333                 struct samu *sampass;
334                 /* The stupid make_server_info_XX functions here
335                    don't take a talloc context. */
336                 struct auth_serversupplied_info *tmp_server_info = NULL;
337
338                 sampass = samu_new(talloc_tos());
339                 if (sampass == NULL) {
340                         status = NT_STATUS_NO_MEMORY;
341                         goto fail;
342                 }
343
344                 if (pdb_getsampwnam(sampass, real_username)) {
345                         DEBUG(10, ("smb2: found user %s in passdb, calling "
346                                 "make_server_info_sam\n", real_username));
347                         status = make_server_info_sam(&tmp_server_info, 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->sam_account != NULL) {
375                         pdb_set_domain(session->server_info->sam_account,
376                                         domain, PDB_SET);
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         /* Fall back to NTLMSSP. */
557         status = auth_ntlmssp_start(&session->auth_ntlmssp_state);
558         if (!NT_STATUS_IS_OK(status)) {
559                 goto out;
560         }
561
562         status = auth_ntlmssp_update(session->auth_ntlmssp_state,
563                                      secblob_in,
564                                      &chal_out);
565
566         if (!NT_STATUS_IS_OK(status) &&
567                         !NT_STATUS_EQUAL(status,
568                                 NT_STATUS_MORE_PROCESSING_REQUIRED)) {
569                 goto out;
570         }
571
572         secblob_out = spnego_gen_auth_response(&chal_out,
573                                                 status,
574                                                 OID_NTLMSSP);
575         *out_security_buffer = data_blob_talloc(smb2req,
576                                                 secblob_out.data,
577                                                 secblob_out.length);
578         if (secblob_out.data && out_security_buffer->data == NULL) {
579                 status = NT_STATUS_NO_MEMORY;
580                 goto out;
581         }
582         *out_session_id = session->vuid;
583
584   out:
585
586         data_blob_free(&secblob_in);
587         data_blob_free(&secblob_out);
588         data_blob_free(&chal_out);
589         SAFE_FREE(kerb_mech);
590         if (!NT_STATUS_IS_OK(status) &&
591                         !NT_STATUS_EQUAL(status,
592                                 NT_STATUS_MORE_PROCESSING_REQUIRED)) {
593                 auth_ntlmssp_end(&session->auth_ntlmssp_state);
594                 TALLOC_FREE(session);
595         }
596         return status;
597 }
598
599 static NTSTATUS smbd_smb2_common_ntlmssp_auth_return(struct smbd_smb2_session *session,
600                                         struct smbd_smb2_request *smb2req,
601                                         uint8_t in_security_mode,
602                                         DATA_BLOB in_security_buffer,
603                                         uint16_t *out_session_flags,
604                                         uint64_t *out_session_id)
605 {
606         fstring tmp;
607
608         if ((in_security_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED) ||
609             lp_server_signing() == Required) {
610                 session->do_signing = true;
611         }
612
613         if (session->auth_ntlmssp_state->server_info->guest) {
614                 /* we map anonymous to guest internally */
615                 *out_session_flags |= SMB2_SESSION_FLAG_IS_GUEST;
616                 *out_session_flags |= SMB2_SESSION_FLAG_IS_NULL;
617                 /* force no signing */
618                 session->do_signing = false;
619         }
620
621         session->server_info = session->auth_ntlmssp_state->server_info;
622         data_blob_free(&session->server_info->user_session_key);
623         session->server_info->user_session_key =
624                 data_blob_talloc(
625                         session->server_info,
626                         session->auth_ntlmssp_state->ntlmssp_state->session_key.data,
627                         session->auth_ntlmssp_state->ntlmssp_state->session_key.length);
628         if (session->auth_ntlmssp_state->ntlmssp_state->session_key.length > 0) {
629                 if (session->server_info->user_session_key.data == NULL) {
630                         auth_ntlmssp_end(&session->auth_ntlmssp_state);
631                         TALLOC_FREE(session);
632                         return NT_STATUS_NO_MEMORY;
633                 }
634         }
635         session->session_key = session->server_info->user_session_key;
636
637         session->compat_vuser = talloc_zero(session, user_struct);
638         if (session->compat_vuser == NULL) {
639                 auth_ntlmssp_end(&session->auth_ntlmssp_state);
640                 TALLOC_FREE(session);
641                 return NT_STATUS_NO_MEMORY;
642         }
643         session->compat_vuser->auth_ntlmssp_state = session->auth_ntlmssp_state;
644         session->compat_vuser->homes_snum = -1;
645         session->compat_vuser->server_info = session->server_info;
646         session->compat_vuser->session_keystr = NULL;
647         session->compat_vuser->vuid = session->vuid;
648         DLIST_ADD(session->sconn->smb1.sessions.validated_users, session->compat_vuser);
649
650         /* This is a potentially untrusted username */
651         alpha_strcpy(tmp,
652                 session->auth_ntlmssp_state->ntlmssp_state->user,
653                 ". _-$",
654                 sizeof(tmp));
655         session->server_info->sanitized_username = talloc_strdup(
656                         session->server_info, tmp);
657
658         if (!session->compat_vuser->server_info->guest) {
659                 session->compat_vuser->homes_snum =
660                         register_homes_share(session->server_info->unix_name);
661         }
662
663         if (!session_claim(session->compat_vuser)) {
664                 DEBUG(1, ("smb2: Failed to claim session "
665                         "for vuid=%d\n",
666                         session->compat_vuser->vuid));
667                 auth_ntlmssp_end(&session->auth_ntlmssp_state);
668                 TALLOC_FREE(session);
669                 return NT_STATUS_LOGON_FAILURE;
670         }
671
672
673         session->status = NT_STATUS_OK;
674
675         /*
676          * we attach the session to the request
677          * so that the response can be signed
678          */
679         smb2req->session = session;
680         if (session->do_signing) {
681                 smb2req->do_signing = true;
682         }
683
684         global_client_caps |= (CAP_LEVEL_II_OPLOCKS|CAP_STATUS32);
685
686         *out_session_id = session->vuid;
687
688         return NT_STATUS_OK;
689 }
690
691 static NTSTATUS smbd_smb2_spnego_auth(struct smbd_smb2_session *session,
692                                         struct smbd_smb2_request *smb2req,
693                                         uint8_t in_security_mode,
694                                         DATA_BLOB in_security_buffer,
695                                         uint16_t *out_session_flags,
696                                         DATA_BLOB *out_security_buffer,
697                                         uint64_t *out_session_id)
698 {
699         DATA_BLOB auth = data_blob_null;
700         DATA_BLOB auth_out = data_blob_null;
701         DATA_BLOB secblob_out = data_blob_null;
702         NTSTATUS status;
703
704         if (!spnego_parse_auth(in_security_buffer, &auth)) {
705                 TALLOC_FREE(session);
706                 return NT_STATUS_LOGON_FAILURE;
707         }
708
709         if (auth.data[0] == ASN1_APPLICATION(0)) {
710                 /* Might be a second negTokenTarg packet */
711                 DATA_BLOB secblob_in = data_blob_null;
712                 char *kerb_mech = NULL;
713
714                 status = parse_spnego_mechanisms(in_security_buffer,
715                                 &secblob_in, &kerb_mech);
716                 if (!NT_STATUS_IS_OK(status)) {
717                         TALLOC_FREE(session);
718                         return status;
719                 }
720
721 #ifdef HAVE_KRB5
722                 if (kerb_mech && ((lp_security()==SEC_ADS) ||
723                                         USE_KERBEROS_KEYTAB) ) {
724                         status = smbd_smb2_session_setup_krb5(session,
725                                         smb2req,
726                                         in_security_mode,
727                                         &secblob_in,
728                                         kerb_mech,
729                                         out_session_flags,
730                                         out_security_buffer,
731                                         out_session_id);
732
733                         data_blob_free(&secblob_in);
734                         SAFE_FREE(kerb_mech);
735                         if (!NT_STATUS_IS_OK(status)) {
736                                 TALLOC_FREE(session);
737                         }
738                         return status;
739                 }
740 #endif
741
742                 /* Can't blunder into NTLMSSP auth if we have
743                  * a krb5 ticket. */
744
745                 if (kerb_mech) {
746                         DEBUG(3,("smb2: network "
747                                 "misconfiguration, client sent us a "
748                                 "krb5 ticket and kerberos security "
749                                 "not enabled\n"));
750                         TALLOC_FREE(session);
751                         data_blob_free(&secblob_in);
752                         SAFE_FREE(kerb_mech);
753                         return NT_STATUS_LOGON_FAILURE;
754                 }
755         }
756
757         status = auth_ntlmssp_update(session->auth_ntlmssp_state,
758                                      auth,
759                                      &auth_out);
760         if (!NT_STATUS_IS_OK(status)) {
761                 auth_ntlmssp_end(&session->auth_ntlmssp_state);
762                 data_blob_free(&auth);
763                 TALLOC_FREE(session);
764                 return status;
765         }
766
767         data_blob_free(&auth);
768
769         secblob_out = spnego_gen_auth_response(&auth_out,
770                                status, NULL);
771
772         *out_security_buffer = data_blob_talloc(smb2req,
773                                                 secblob_out.data,
774                                                 secblob_out.length);
775         if (secblob_out.data && out_security_buffer->data == NULL) {
776                 auth_ntlmssp_end(&session->auth_ntlmssp_state);
777                 TALLOC_FREE(session);
778                 return NT_STATUS_NO_MEMORY;
779         }
780
781         *out_session_id = session->vuid;
782
783         return smbd_smb2_common_ntlmssp_auth_return(session,
784                                                 smb2req,
785                                                 in_security_mode,
786                                                 in_security_buffer,
787                                                 out_session_flags,
788                                                 out_session_id);
789 }
790
791 static NTSTATUS smbd_smb2_raw_ntlmssp_auth(struct smbd_smb2_session *session,
792                                         struct smbd_smb2_request *smb2req,
793                                         uint8_t in_security_mode,
794                                         DATA_BLOB in_security_buffer,
795                                         uint16_t *out_session_flags,
796                                         DATA_BLOB *out_security_buffer,
797                                         uint64_t *out_session_id)
798 {
799         NTSTATUS status;
800         DATA_BLOB secblob_out = data_blob_null;
801
802         if (session->auth_ntlmssp_state == NULL) {
803                 status = auth_ntlmssp_start(&session->auth_ntlmssp_state);
804                 if (!NT_STATUS_IS_OK(status)) {
805                         TALLOC_FREE(session);
806                         return status;
807                 }
808         }
809
810         /* RAW NTLMSSP */
811         status = auth_ntlmssp_update(session->auth_ntlmssp_state,
812                                      in_security_buffer,
813                                      &secblob_out);
814
815         if (NT_STATUS_IS_OK(status) ||
816                         NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
817                 *out_security_buffer = data_blob_talloc(smb2req,
818                                                 secblob_out.data,
819                                                 secblob_out.length);
820                 if (secblob_out.data && out_security_buffer->data == NULL) {
821                         auth_ntlmssp_end(&session->auth_ntlmssp_state);
822                         TALLOC_FREE(session);
823                         return NT_STATUS_NO_MEMORY;
824                 }
825         }
826
827         if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
828                 *out_session_id = session->vuid;
829                 return status;
830         }
831         if (!NT_STATUS_IS_OK(status)) {
832                 auth_ntlmssp_end(&session->auth_ntlmssp_state);
833                 TALLOC_FREE(session);
834                 return status;
835         }
836         *out_session_id = session->vuid;
837
838         return smbd_smb2_common_ntlmssp_auth_return(session,
839                                                 smb2req,
840                                                 in_security_mode,
841                                                 in_security_buffer,
842                                                 out_session_flags,
843                                                 out_session_id);
844 }
845
846 static NTSTATUS smbd_smb2_session_setup(struct smbd_smb2_request *smb2req,
847                                         uint64_t in_session_id,
848                                         uint8_t in_security_mode,
849                                         DATA_BLOB in_security_buffer,
850                                         uint16_t *out_session_flags,
851                                         DATA_BLOB *out_security_buffer,
852                                         uint64_t *out_session_id)
853 {
854         struct smbd_smb2_session *session;
855
856         *out_session_flags = 0;
857         *out_session_id = 0;
858
859         if (in_session_id == 0) {
860                 int id;
861
862                 /* create a new session */
863                 session = talloc_zero(smb2req->sconn, struct smbd_smb2_session);
864                 if (session == NULL) {
865                         return NT_STATUS_NO_MEMORY;
866                 }
867                 session->status = NT_STATUS_MORE_PROCESSING_REQUIRED;
868                 id = idr_get_new_random(smb2req->sconn->smb2.sessions.idtree,
869                                         session,
870                                         smb2req->sconn->smb2.sessions.limit);
871                 if (id == -1) {
872                         return NT_STATUS_INSUFFICIENT_RESOURCES;
873                 }
874                 session->vuid = id;
875
876                 session->tcons.idtree = idr_init(session);
877                 if (session->tcons.idtree == NULL) {
878                         return NT_STATUS_NO_MEMORY;
879                 }
880                 session->tcons.limit = 0x0000FFFE;
881                 session->tcons.list = NULL;
882
883                 DLIST_ADD_END(smb2req->sconn->smb2.sessions.list, session,
884                               struct smbd_smb2_session *);
885                 session->sconn = smb2req->sconn;
886                 talloc_set_destructor(session, smbd_smb2_session_destructor);
887         } else {
888                 void *p;
889
890                 /* lookup an existing session */
891                 p = idr_find(smb2req->sconn->smb2.sessions.idtree, in_session_id);
892                 if (p == NULL) {
893                         return NT_STATUS_USER_SESSION_DELETED;
894                 }
895                 session = talloc_get_type_abort(p, struct smbd_smb2_session);
896         }
897
898         if (NT_STATUS_IS_OK(session->status)) {
899                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
900         }
901
902         if (in_security_buffer.data[0] == ASN1_APPLICATION(0)) {
903                 return smbd_smb2_spnego_negotiate(session,
904                                                 smb2req,
905                                                 in_security_mode,
906                                                 in_security_buffer,
907                                                 out_session_flags,
908                                                 out_security_buffer,
909                                                 out_session_id);
910         } else if (in_security_buffer.data[0] == ASN1_CONTEXT(1)) {
911                 return smbd_smb2_spnego_auth(session,
912                                                 smb2req,
913                                                 in_security_mode,
914                                                 in_security_buffer,
915                                                 out_session_flags,
916                                                 out_security_buffer,
917                                                 out_session_id);
918         } else if (strncmp((char *)(in_security_buffer.data), "NTLMSSP", 7) == 0) {
919                 return smbd_smb2_raw_ntlmssp_auth(session,
920                                                 smb2req,
921                                                 in_security_mode,
922                                                 in_security_buffer,
923                                                 out_session_flags,
924                                                 out_security_buffer,
925                                                 out_session_id);
926         }
927
928         /* Unknown packet type. */
929         DEBUG(1,("Unknown packet type %u in smb2 sessionsetup\n",
930                 (unsigned int)in_security_buffer.data[0] ));
931         auth_ntlmssp_end(&session->auth_ntlmssp_state);
932         TALLOC_FREE(session);
933         return NT_STATUS_LOGON_FAILURE;
934 }
935
936 NTSTATUS smbd_smb2_request_check_session(struct smbd_smb2_request *req)
937 {
938         const uint8_t *inhdr;
939         const uint8_t *outhdr;
940         int i = req->current_idx;
941         uint64_t in_session_id;
942         void *p;
943         struct smbd_smb2_session *session;
944         bool chained_fixup = false;
945
946         inhdr = (const uint8_t *)req->in.vector[i+0].iov_base;
947
948         in_session_id = BVAL(inhdr, SMB2_HDR_SESSION_ID);
949
950         if (in_session_id == (0xFFFFFFFFFFFFFFFFLL)) {
951                 if (req->async) {
952                         /*
953                          * async request - fill in session_id from
954                          * already setup request out.vector[].iov_base.
955                          */
956                         outhdr = (const uint8_t *)req->out.vector[i].iov_base;
957                         in_session_id = BVAL(outhdr, SMB2_HDR_SESSION_ID);
958                 } else if (i > 2) {
959                         /*
960                          * Chained request - fill in session_id from
961                          * the previous request out.vector[].iov_base.
962                          */
963                         outhdr = (const uint8_t *)req->out.vector[i-3].iov_base;
964                         in_session_id = BVAL(outhdr, SMB2_HDR_SESSION_ID);
965                         chained_fixup = true;
966                 }
967         }
968
969         /* lookup an existing session */
970         p = idr_find(req->sconn->smb2.sessions.idtree, in_session_id);
971         if (p == NULL) {
972                 return NT_STATUS_USER_SESSION_DELETED;
973         }
974         session = talloc_get_type_abort(p, struct smbd_smb2_session);
975
976         if (!NT_STATUS_IS_OK(session->status)) {
977                 return NT_STATUS_ACCESS_DENIED;
978         }
979
980         set_current_user_info(session->server_info->sanitized_username,
981                               session->server_info->unix_name,
982                               pdb_get_domain(session->server_info->sam_account));
983
984         req->session = session;
985
986         if (chained_fixup) {
987                 /* Fix up our own outhdr. */
988                 outhdr = (const uint8_t *)req->out.vector[i].iov_base;
989                 SBVAL(outhdr, SMB2_HDR_SESSION_ID, in_session_id);
990         }
991         return NT_STATUS_OK;
992 }
993
994 NTSTATUS smbd_smb2_request_process_logoff(struct smbd_smb2_request *req)
995 {
996         const uint8_t *inbody;
997         int i = req->current_idx;
998         DATA_BLOB outbody;
999         size_t expected_body_size = 0x04;
1000         size_t body_size;
1001
1002         if (req->in.vector[i+1].iov_len != (expected_body_size & 0xFFFFFFFE)) {
1003                 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
1004         }
1005
1006         inbody = (const uint8_t *)req->in.vector[i+1].iov_base;
1007
1008         body_size = SVAL(inbody, 0x00);
1009         if (body_size != expected_body_size) {
1010                 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
1011         }
1012
1013         /*
1014          * TODO: cancel all outstanding requests on the session
1015          *       and delete all tree connections.
1016          */
1017         smbd_smb2_session_destructor(req->session);
1018         /*
1019          * we may need to sign the response, so we need to keep
1020          * the session until the response is sent to the wire.
1021          */
1022         talloc_steal(req, req->session);
1023
1024         outbody = data_blob_talloc(req->out.vector, NULL, 0x04);
1025         if (outbody.data == NULL) {
1026                 return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
1027         }
1028
1029         SSVAL(outbody.data, 0x00, 0x04);        /* struct size */
1030         SSVAL(outbody.data, 0x02, 0);           /* reserved */
1031
1032         return smbd_smb2_request_done(req, outbody, NULL);
1033 }