966289429d9ba5d213c79936f52205e0a282517f
[kai/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 static NTSTATUS smbd_smb2_session_setup_krb5(struct smbd_smb2_session *session,
147                                         struct smbd_smb2_request *smb2req,
148                                         uint8_t in_security_mode,
149                                         const DATA_BLOB *secblob,
150                                         const char *mechOID,
151                                         uint16_t *out_session_flags,
152                                         DATA_BLOB *out_security_buffer,
153                                         uint64_t *out_session_id)
154 {
155         DATA_BLOB ap_rep = data_blob_null;
156         DATA_BLOB ap_rep_wrapped = data_blob_null;
157         DATA_BLOB ticket = data_blob_null;
158         DATA_BLOB session_key = data_blob_null;
159         DATA_BLOB secblob_out = data_blob_null;
160         uint8 tok_id[2];
161         struct PAC_LOGON_INFO *logon_info = NULL;
162         char *client = NULL;
163         char *p = NULL;
164         char *domain = NULL;
165         struct passwd *pw = NULL;
166         NTSTATUS status;
167         fstring user;
168         fstring real_username;
169         fstring tmp;
170         bool username_was_mapped = false;
171         bool map_domainuser_to_guest = false;
172         struct smbd_server_connection *sconn = smbd_server_conn;
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(sconn, 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                 } else {
348                         /*
349                          * User not in passdb, make it up artificially
350                          */
351                         TALLOC_FREE(sampass);
352                         DEBUG(10, ("smb2: didn't find user %s in passdb, calling "
353                                 "make_server_info_pw\n", real_username));
354                         status = make_server_info_pw(&tmp_server_info,
355                                         real_username,
356                                         pw);
357                 }
358
359                 if (!NT_STATUS_IS_OK(status)) {
360                         DEBUG(1,("smb2: make_server_info_[sam|pw] failed: %s!\n",
361                                 nt_errstr(status)));
362                         goto fail;
363                 }
364
365                 /* Steal tmp_server_info into the session->server_info
366                    pointer. */
367                 session->server_info = talloc_move(session, &tmp_server_info);
368
369                 /* make_server_info_pw does not set the domain. Without this
370                  * we end up with the local netbios name in substitutions for
371                  * %D. */
372
373                 if (session->server_info->sam_account != NULL) {
374                         pdb_set_domain(session->server_info->sam_account,
375                                         domain, PDB_SET);
376                 }
377
378         }
379
380         session->server_info->nss_token |= username_was_mapped;
381
382         /* we need to build the token for the user. make_server_info_guest()
383            already does this */
384
385         if (!session->server_info->ptok ) {
386                 status = create_local_token(session->server_info);
387                 if (!NT_STATUS_IS_OK(status)) {
388                         DEBUG(10,("smb2: failed to create local token: %s\n",
389                                 nt_errstr(status)));
390                         goto fail;
391                 }
392         }
393
394         if ((in_security_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED) ||
395              lp_server_signing() == Required) {
396                 session->do_signing = true;
397         }
398
399         if (session->server_info->guest) {
400                 /* we map anonymous to guest internally */
401                 *out_session_flags |= SMB2_SESSION_FLAG_IS_GUEST;
402                 *out_session_flags |= SMB2_SESSION_FLAG_IS_NULL;
403                 /* force no signing */
404                 session->do_signing = false;
405         }
406
407         data_blob_free(&session->server_info->user_session_key);
408         session->server_info->user_session_key =
409                         data_blob_talloc(
410                                 session->server_info,
411                                 session_key.data,
412                                 session_key.length);
413         if (session_key.length > 0) {
414                 if (session->server_info->user_session_key.data == NULL) {
415                         status = NT_STATUS_NO_MEMORY;
416                         goto fail;
417                 }
418         }
419         session->session_key = session->server_info->user_session_key;
420
421         session->compat_vuser = talloc_zero(session, user_struct);
422         if (session->compat_vuser == NULL) {
423                 status = NT_STATUS_NO_MEMORY;
424                 goto fail;
425         }
426         session->compat_vuser->auth_ntlmssp_state = NULL;
427         session->compat_vuser->homes_snum = -1;
428         session->compat_vuser->server_info = session->server_info;
429         session->compat_vuser->session_keystr = NULL;
430         session->compat_vuser->vuid = session->vuid;
431         DLIST_ADD(session->sconn->smb1.sessions.validated_users, session->compat_vuser);
432
433         /* This is a potentially untrusted username */
434         alpha_strcpy(tmp,
435                 client,
436                 ". _-$",
437                 sizeof(tmp));
438         session->server_info->sanitized_username = talloc_strdup(
439                         session->server_info, tmp);
440
441         if (!session->server_info->guest) {
442                 session->compat_vuser->homes_snum =
443                         register_homes_share(session->server_info->unix_name);
444         }
445
446         if (!session_claim(session->compat_vuser)) {
447                 DEBUG(1, ("smb2: Failed to claim session "
448                         "for vuid=%d\n",
449                         session->compat_vuser->vuid));
450                 goto fail;
451         }
452
453         session->status = NT_STATUS_OK;
454
455         /*
456          * we attach the session to the request
457          * so that the response can be signed
458          */
459         smb2req->session = session;
460         if (session->do_signing) {
461                 smb2req->do_signing = true;
462         }
463
464         global_client_caps |= (CAP_LEVEL_II_OPLOCKS|CAP_STATUS32);
465         status = NT_STATUS_OK;
466
467         /* wrap that up in a nice GSS-API wrapping */
468         ap_rep_wrapped = spnego_gen_krb5_wrap(ap_rep,
469                                 TOK_ID_KRB_AP_REP);
470
471         secblob_out = spnego_gen_auth_response(
472                                         &ap_rep_wrapped,
473                                         status,
474                                         mechOID);
475
476         *out_security_buffer = data_blob_talloc(smb2req,
477                                                 secblob_out.data,
478                                                 secblob_out.length);
479         if (secblob_out.data && out_security_buffer->data == NULL) {
480                 status = NT_STATUS_NO_MEMORY;
481                 goto fail;
482         }
483
484         data_blob_free(&ap_rep);
485         data_blob_free(&ap_rep_wrapped);
486         data_blob_free(&ticket);
487         data_blob_free(&session_key);
488         data_blob_free(&secblob_out);
489
490         *out_session_id = session->vuid;
491
492         return NT_STATUS_OK;
493
494   fail:
495
496         data_blob_free(&ap_rep);
497         data_blob_free(&ap_rep_wrapped);
498         data_blob_free(&ticket);
499         data_blob_free(&session_key);
500         data_blob_free(&secblob_out);
501
502         ap_rep_wrapped = data_blob_null;
503         secblob_out = spnego_gen_auth_response(
504                                         &ap_rep_wrapped,
505                                         status,
506                                         mechOID);
507
508         *out_security_buffer = data_blob_talloc(smb2req,
509                                                 secblob_out.data,
510                                                 secblob_out.length);
511         data_blob_free(&secblob_out);
512         return status;
513 }
514
515 static NTSTATUS smbd_smb2_spnego_negotiate(struct smbd_smb2_session *session,
516                                         struct smbd_smb2_request *smb2req,
517                                         uint8_t in_security_flags,
518                                         DATA_BLOB in_security_buffer,
519                                         uint16_t *out_session_flags,
520                                         DATA_BLOB *out_security_buffer,
521                                         uint64_t *out_session_id)
522 {
523         DATA_BLOB secblob_in = data_blob_null;
524         DATA_BLOB chal_out = data_blob_null;
525         DATA_BLOB secblob_out = data_blob_null;
526         char *kerb_mech = NULL;
527         NTSTATUS status;
528
529         /* Ensure we have no old NTLM state around. */
530         auth_ntlmssp_end(&session->auth_ntlmssp_state);
531
532         status = parse_spnego_mechanisms(in_security_buffer,
533                         &secblob_in, &kerb_mech);
534         if (!NT_STATUS_IS_OK(status)) {
535                 goto out;
536         }
537
538 #ifdef HAVE_KRB5
539         if (kerb_mech && ((lp_security()==SEC_ADS) ||
540                                 USE_KERBEROS_KEYTAB) ) {
541                 status = smbd_smb2_session_setup_krb5(session,
542                                 smb2req,
543                                 in_security_flags,
544                                 &secblob_in,
545                                 kerb_mech,
546                                 out_session_flags,
547                                 out_security_buffer,
548                                 out_session_id);
549
550                 goto out;
551         }
552 #endif
553
554         /* Fall back to NTLMSSP. */
555         status = auth_ntlmssp_start(&session->auth_ntlmssp_state);
556         if (!NT_STATUS_IS_OK(status)) {
557                 goto out;
558         }
559
560         status = auth_ntlmssp_update(session->auth_ntlmssp_state,
561                                      secblob_in,
562                                      &chal_out);
563
564         if (!NT_STATUS_IS_OK(status) &&
565                         !NT_STATUS_EQUAL(status,
566                                 NT_STATUS_MORE_PROCESSING_REQUIRED)) {
567                 goto out;
568         }
569
570         secblob_out = spnego_gen_auth_response(&chal_out,
571                                                 status,
572                                                 OID_NTLMSSP);
573         *out_security_buffer = data_blob_talloc(smb2req,
574                                                 secblob_out.data,
575                                                 secblob_out.length);
576         if (secblob_out.data && out_security_buffer->data == NULL) {
577                 status = NT_STATUS_NO_MEMORY;
578                 goto out;
579         }
580         *out_session_id = session->vuid;
581
582   out:
583
584         data_blob_free(&secblob_in);
585         data_blob_free(&secblob_out);
586         data_blob_free(&chal_out);
587         SAFE_FREE(kerb_mech);
588         if (!NT_STATUS_IS_OK(status) &&
589                         !NT_STATUS_EQUAL(status,
590                                 NT_STATUS_MORE_PROCESSING_REQUIRED)) {
591                 auth_ntlmssp_end(&session->auth_ntlmssp_state);
592                 TALLOC_FREE(session);
593         }
594         return status;
595 }
596
597 static NTSTATUS smbd_smb2_common_ntlmssp_auth_return(struct smbd_smb2_session *session,
598                                         struct smbd_smb2_request *smb2req,
599                                         uint8_t in_security_mode,
600                                         DATA_BLOB in_security_buffer,
601                                         uint16_t *out_session_flags,
602                                         uint64_t *out_session_id)
603 {
604         fstring tmp;
605
606         if ((in_security_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED) ||
607             lp_server_signing() == Required) {
608                 session->do_signing = true;
609         }
610
611         if (session->auth_ntlmssp_state->server_info->guest) {
612                 /* we map anonymous to guest internally */
613                 *out_session_flags |= SMB2_SESSION_FLAG_IS_GUEST;
614                 *out_session_flags |= SMB2_SESSION_FLAG_IS_NULL;
615                 /* force no signing */
616                 session->do_signing = false;
617         }
618
619         session->server_info = session->auth_ntlmssp_state->server_info;
620         data_blob_free(&session->server_info->user_session_key);
621         session->server_info->user_session_key =
622                 data_blob_talloc(
623                         session->server_info,
624                         session->auth_ntlmssp_state->ntlmssp_state->session_key.data,
625                         session->auth_ntlmssp_state->ntlmssp_state->session_key.length);
626         if (session->auth_ntlmssp_state->ntlmssp_state->session_key.length > 0) {
627                 if (session->server_info->user_session_key.data == NULL) {
628                         auth_ntlmssp_end(&session->auth_ntlmssp_state);
629                         TALLOC_FREE(session);
630                         return NT_STATUS_NO_MEMORY;
631                 }
632         }
633         session->session_key = session->server_info->user_session_key;
634
635         session->compat_vuser = talloc_zero(session, user_struct);
636         if (session->compat_vuser == NULL) {
637                 auth_ntlmssp_end(&session->auth_ntlmssp_state);
638                 TALLOC_FREE(session);
639                 return NT_STATUS_NO_MEMORY;
640         }
641         session->compat_vuser->auth_ntlmssp_state = session->auth_ntlmssp_state;
642         session->compat_vuser->homes_snum = -1;
643         session->compat_vuser->server_info = session->server_info;
644         session->compat_vuser->session_keystr = NULL;
645         session->compat_vuser->vuid = session->vuid;
646         DLIST_ADD(session->sconn->smb1.sessions.validated_users, session->compat_vuser);
647
648         /* This is a potentially untrusted username */
649         alpha_strcpy(tmp,
650                 session->auth_ntlmssp_state->ntlmssp_state->user,
651                 ". _-$",
652                 sizeof(tmp));
653         session->server_info->sanitized_username = talloc_strdup(
654                         session->server_info, tmp);
655
656         if (!session->compat_vuser->server_info->guest) {
657                 session->compat_vuser->homes_snum =
658                         register_homes_share(session->server_info->unix_name);
659         }
660
661         if (!session_claim(session->compat_vuser)) {
662                 DEBUG(1, ("smb2: Failed to claim session "
663                         "for vuid=%d\n",
664                         session->compat_vuser->vuid));
665                 auth_ntlmssp_end(&session->auth_ntlmssp_state);
666                 TALLOC_FREE(session);
667                 return NT_STATUS_LOGON_FAILURE;
668         }
669
670
671         session->status = NT_STATUS_OK;
672
673         /*
674          * we attach the session to the request
675          * so that the response can be signed
676          */
677         smb2req->session = session;
678         if (session->do_signing) {
679                 smb2req->do_signing = true;
680         }
681
682         global_client_caps |= (CAP_LEVEL_II_OPLOCKS|CAP_STATUS32);
683
684         *out_session_id = session->vuid;
685
686         return NT_STATUS_OK;
687 }
688
689 static NTSTATUS smbd_smb2_spnego_auth(struct smbd_smb2_session *session,
690                                         struct smbd_smb2_request *smb2req,
691                                         uint8_t in_security_mode,
692                                         DATA_BLOB in_security_buffer,
693                                         uint16_t *out_session_flags,
694                                         DATA_BLOB *out_security_buffer,
695                                         uint64_t *out_session_id)
696 {
697         DATA_BLOB auth = data_blob_null;
698         DATA_BLOB auth_out = data_blob_null;
699         DATA_BLOB secblob_out = data_blob_null;
700         NTSTATUS status;
701
702         if (!spnego_parse_auth(in_security_buffer, &auth)) {
703                 TALLOC_FREE(session);
704                 return NT_STATUS_LOGON_FAILURE;
705         }
706
707         status = auth_ntlmssp_update(session->auth_ntlmssp_state,
708                                      auth,
709                                      &auth_out);
710         if (!NT_STATUS_IS_OK(status)) {
711                 auth_ntlmssp_end(&session->auth_ntlmssp_state);
712                 data_blob_free(&auth);
713                 TALLOC_FREE(session);
714                 return status;
715         }
716
717         data_blob_free(&auth);
718
719         secblob_out = spnego_gen_auth_response(&auth_out,
720                                status, NULL);
721
722         *out_security_buffer = data_blob_talloc(smb2req,
723                                                 secblob_out.data,
724                                                 secblob_out.length);
725         if (secblob_out.data && out_security_buffer->data == NULL) {
726                 auth_ntlmssp_end(&session->auth_ntlmssp_state);
727                 TALLOC_FREE(session);
728                 return NT_STATUS_NO_MEMORY;
729         }
730
731         *out_session_id = session->vuid;
732
733         return smbd_smb2_common_ntlmssp_auth_return(session,
734                                                 smb2req,
735                                                 in_security_mode,
736                                                 in_security_buffer,
737                                                 out_session_flags,
738                                                 out_session_id);
739 }
740
741 static NTSTATUS smbd_smb2_raw_ntlmssp_auth(struct smbd_smb2_session *session,
742                                         struct smbd_smb2_request *smb2req,
743                                         uint8_t in_security_mode,
744                                         DATA_BLOB in_security_buffer,
745                                         uint16_t *out_session_flags,
746                                         DATA_BLOB *out_security_buffer,
747                                         uint64_t *out_session_id)
748 {
749         NTSTATUS status;
750         DATA_BLOB secblob_out = data_blob_null;
751
752         if (session->auth_ntlmssp_state == NULL) {
753                 status = auth_ntlmssp_start(&session->auth_ntlmssp_state);
754                 if (!NT_STATUS_IS_OK(status)) {
755                         TALLOC_FREE(session);
756                         return status;
757                 }
758         }
759
760         /* RAW NTLMSSP */
761         status = auth_ntlmssp_update(session->auth_ntlmssp_state,
762                                      in_security_buffer,
763                                      &secblob_out);
764
765         if (NT_STATUS_IS_OK(status) ||
766                         NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
767                 *out_security_buffer = data_blob_talloc(smb2req,
768                                                 secblob_out.data,
769                                                 secblob_out.length);
770                 if (secblob_out.data && out_security_buffer->data == NULL) {
771                         auth_ntlmssp_end(&session->auth_ntlmssp_state);
772                         TALLOC_FREE(session);
773                         return NT_STATUS_NO_MEMORY;
774                 }
775         }
776
777         if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
778                 *out_session_id = session->vuid;
779                 return status;
780         }
781         if (!NT_STATUS_IS_OK(status)) {
782                 auth_ntlmssp_end(&session->auth_ntlmssp_state);
783                 TALLOC_FREE(session);
784                 return status;
785         }
786         *out_session_id = session->vuid;
787
788         return smbd_smb2_common_ntlmssp_auth_return(session,
789                                                 smb2req,
790                                                 in_security_mode,
791                                                 in_security_buffer,
792                                                 out_session_flags,
793                                                 out_session_id);
794 }
795
796 static NTSTATUS smbd_smb2_session_setup(struct smbd_smb2_request *smb2req,
797                                         uint64_t in_session_id,
798                                         uint8_t in_security_mode,
799                                         DATA_BLOB in_security_buffer,
800                                         uint16_t *out_session_flags,
801                                         DATA_BLOB *out_security_buffer,
802                                         uint64_t *out_session_id)
803 {
804         struct smbd_smb2_session *session;
805
806         *out_session_flags = 0;
807         *out_session_id = 0;
808
809         if (in_session_id == 0) {
810                 int id;
811
812                 /* create a new session */
813                 session = talloc_zero(smb2req->sconn, struct smbd_smb2_session);
814                 if (session == NULL) {
815                         return NT_STATUS_NO_MEMORY;
816                 }
817                 session->status = NT_STATUS_MORE_PROCESSING_REQUIRED;
818                 id = idr_get_new_random(smb2req->sconn->smb2.sessions.idtree,
819                                         session,
820                                         smb2req->sconn->smb2.sessions.limit);
821                 if (id == -1) {
822                         return NT_STATUS_INSUFFICIENT_RESOURCES;
823                 }
824                 session->vuid = id;
825
826                 session->tcons.idtree = idr_init(session);
827                 if (session->tcons.idtree == NULL) {
828                         return NT_STATUS_NO_MEMORY;
829                 }
830                 session->tcons.limit = 0x0000FFFE;
831                 session->tcons.list = NULL;
832
833                 DLIST_ADD_END(smb2req->sconn->smb2.sessions.list, session,
834                               struct smbd_smb2_session *);
835                 session->sconn = smb2req->sconn;
836                 talloc_set_destructor(session, smbd_smb2_session_destructor);
837         } else {
838                 void *p;
839
840                 /* lookup an existing session */
841                 p = idr_find(smb2req->sconn->smb2.sessions.idtree, in_session_id);
842                 if (p == NULL) {
843                         return NT_STATUS_USER_SESSION_DELETED;
844                 }
845                 session = talloc_get_type_abort(p, struct smbd_smb2_session);
846         }
847
848         if (NT_STATUS_IS_OK(session->status)) {
849                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
850         }
851
852         if (in_security_buffer.data[0] == ASN1_APPLICATION(0)) {
853                 return smbd_smb2_spnego_negotiate(session,
854                                                 smb2req,
855                                                 in_security_mode,
856                                                 in_security_buffer,
857                                                 out_session_flags,
858                                                 out_security_buffer,
859                                                 out_session_id);
860         } else if (in_security_buffer.data[0] == ASN1_CONTEXT(1)) {
861                 return smbd_smb2_spnego_auth(session,
862                                                 smb2req,
863                                                 in_security_mode,
864                                                 in_security_buffer,
865                                                 out_session_flags,
866                                                 out_security_buffer,
867                                                 out_session_id);
868         } else if (strncmp((char *)(in_security_buffer.data), "NTLMSSP", 7) == 0) {
869                 return smbd_smb2_raw_ntlmssp_auth(session,
870                                                 smb2req,
871                                                 in_security_mode,
872                                                 in_security_buffer,
873                                                 out_session_flags,
874                                                 out_security_buffer,
875                                                 out_session_id);
876         }
877
878         /* Unknown packet type. */
879         DEBUG(1,("Unknown packet type %u in smb2 sessionsetup\n",
880                 (unsigned int)in_security_buffer.data[0] ));
881         auth_ntlmssp_end(&session->auth_ntlmssp_state);
882         TALLOC_FREE(session);
883         return NT_STATUS_LOGON_FAILURE;
884 }
885
886 NTSTATUS smbd_smb2_request_check_session(struct smbd_smb2_request *req)
887 {
888         const uint8_t *inhdr;
889         const uint8_t *outhdr;
890         int i = req->current_idx;
891         uint64_t in_session_id;
892         void *p;
893         struct smbd_smb2_session *session;
894         bool chained_fixup = false;
895
896         inhdr = (const uint8_t *)req->in.vector[i+0].iov_base;
897
898         in_session_id = BVAL(inhdr, SMB2_HDR_SESSION_ID);
899
900         if (in_session_id == (0xFFFFFFFFFFFFFFFFLL)) {
901                 if (req->async) {
902                         /*
903                          * async request - fill in session_id from
904                          * already setup request out.vector[].iov_base.
905                          */
906                         outhdr = (const uint8_t *)req->out.vector[i].iov_base;
907                         in_session_id = BVAL(outhdr, SMB2_HDR_SESSION_ID);
908                 } else if (i > 2) {
909                         /*
910                          * Chained request - fill in session_id from
911                          * the previous request out.vector[].iov_base.
912                          */
913                         outhdr = (const uint8_t *)req->out.vector[i-3].iov_base;
914                         in_session_id = BVAL(outhdr, SMB2_HDR_SESSION_ID);
915                         chained_fixup = true;
916                 }
917         }
918
919         /* lookup an existing session */
920         p = idr_find(req->sconn->smb2.sessions.idtree, in_session_id);
921         if (p == NULL) {
922                 return NT_STATUS_USER_SESSION_DELETED;
923         }
924         session = talloc_get_type_abort(p, struct smbd_smb2_session);
925
926         if (!NT_STATUS_IS_OK(session->status)) {
927                 return NT_STATUS_ACCESS_DENIED;
928         }
929
930         set_current_user_info(session->server_info->sanitized_username,
931                               session->server_info->unix_name,
932                               pdb_get_domain(session->server_info->sam_account));
933
934         req->session = session;
935
936         if (chained_fixup) {
937                 /* Fix up our own outhdr. */
938                 outhdr = (const uint8_t *)req->out.vector[i].iov_base;
939                 SBVAL(outhdr, SMB2_HDR_SESSION_ID, in_session_id);
940         }
941         return NT_STATUS_OK;
942 }
943
944 NTSTATUS smbd_smb2_request_process_logoff(struct smbd_smb2_request *req)
945 {
946         const uint8_t *inbody;
947         int i = req->current_idx;
948         DATA_BLOB outbody;
949         size_t expected_body_size = 0x04;
950         size_t body_size;
951
952         if (req->in.vector[i+1].iov_len != (expected_body_size & 0xFFFFFFFE)) {
953                 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
954         }
955
956         inbody = (const uint8_t *)req->in.vector[i+1].iov_base;
957
958         body_size = SVAL(inbody, 0x00);
959         if (body_size != expected_body_size) {
960                 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
961         }
962
963         /*
964          * TODO: cancel all outstanding requests on the session
965          *       and delete all tree connections.
966          */
967         smbd_smb2_session_destructor(req->session);
968         /*
969          * we may need to sign the response, so we need to keep
970          * the session until the response is sent to the wire.
971          */
972         talloc_steal(req, req->session);
973
974         outbody = data_blob_talloc(req->out.vector, NULL, 0x04);
975         if (outbody.data == NULL) {
976                 return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
977         }
978
979         SSVAL(outbody.data, 0x00, 0x04);        /* struct size */
980         SSVAL(outbody.data, 0x02, 0);           /* reserved */
981
982         return smbd_smb2_request_done(req, outbody, NULL);
983 }