s3: Remove procid_self() from session_claim()
[amitay/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(sconn_server_id(session->sconn),
448                            session->compat_vuser)) {
449                 DEBUG(1, ("smb2: Failed to claim session "
450                         "for vuid=%d\n",
451                         session->compat_vuser->vuid));
452                 goto fail;
453         }
454
455         session->status = NT_STATUS_OK;
456
457         /*
458          * we attach the session to the request
459          * so that the response can be signed
460          */
461         smb2req->session = session;
462         if (session->do_signing) {
463                 smb2req->do_signing = true;
464         }
465
466         global_client_caps |= (CAP_LEVEL_II_OPLOCKS|CAP_STATUS32);
467         status = NT_STATUS_OK;
468
469         /* wrap that up in a nice GSS-API wrapping */
470         ap_rep_wrapped = spnego_gen_krb5_wrap(ap_rep,
471                                 TOK_ID_KRB_AP_REP);
472
473         secblob_out = spnego_gen_auth_response(
474                                         &ap_rep_wrapped,
475                                         status,
476                                         mechOID);
477
478         *out_security_buffer = data_blob_talloc(smb2req,
479                                                 secblob_out.data,
480                                                 secblob_out.length);
481         if (secblob_out.data && out_security_buffer->data == NULL) {
482                 status = NT_STATUS_NO_MEMORY;
483                 goto fail;
484         }
485
486         data_blob_free(&ap_rep);
487         data_blob_free(&ap_rep_wrapped);
488         data_blob_free(&ticket);
489         data_blob_free(&session_key);
490         data_blob_free(&secblob_out);
491
492         *out_session_id = session->vuid;
493
494         return NT_STATUS_OK;
495
496   fail:
497
498         data_blob_free(&ap_rep);
499         data_blob_free(&ap_rep_wrapped);
500         data_blob_free(&ticket);
501         data_blob_free(&session_key);
502         data_blob_free(&secblob_out);
503
504         ap_rep_wrapped = data_blob_null;
505         secblob_out = spnego_gen_auth_response(
506                                         &ap_rep_wrapped,
507                                         status,
508                                         mechOID);
509
510         *out_security_buffer = data_blob_talloc(smb2req,
511                                                 secblob_out.data,
512                                                 secblob_out.length);
513         data_blob_free(&secblob_out);
514         return status;
515 }
516 #endif
517
518 static NTSTATUS smbd_smb2_spnego_negotiate(struct smbd_smb2_session *session,
519                                         struct smbd_smb2_request *smb2req,
520                                         uint8_t in_security_mode,
521                                         DATA_BLOB in_security_buffer,
522                                         uint16_t *out_session_flags,
523                                         DATA_BLOB *out_security_buffer,
524                                         uint64_t *out_session_id)
525 {
526         DATA_BLOB secblob_in = data_blob_null;
527         DATA_BLOB chal_out = data_blob_null;
528         DATA_BLOB secblob_out = data_blob_null;
529         char *kerb_mech = NULL;
530         NTSTATUS status;
531
532         /* Ensure we have no old NTLM state around. */
533         auth_ntlmssp_end(&session->auth_ntlmssp_state);
534
535         status = parse_spnego_mechanisms(in_security_buffer,
536                         &secblob_in, &kerb_mech);
537         if (!NT_STATUS_IS_OK(status)) {
538                 goto out;
539         }
540
541 #ifdef HAVE_KRB5
542         if (kerb_mech && ((lp_security()==SEC_ADS) ||
543                                 USE_KERBEROS_KEYTAB) ) {
544                 status = smbd_smb2_session_setup_krb5(session,
545                                 smb2req,
546                                 in_security_mode,
547                                 &secblob_in,
548                                 kerb_mech,
549                                 out_session_flags,
550                                 out_security_buffer,
551                                 out_session_id);
552
553                 goto out;
554         }
555 #endif
556
557         if (kerb_mech) {
558                 /* The mechtoken is a krb5 ticket, but
559                  * we need to fall back to NTLM. */
560
561                 DEBUG(3,("smb2: Got krb5 ticket in SPNEGO "
562                         "but set to downgrade to NTLMSSP\n"));
563
564                 status = NT_STATUS_MORE_PROCESSING_REQUIRED;
565         } else {
566                 /* Fall back to NTLMSSP. */
567                 status = auth_ntlmssp_start(&session->auth_ntlmssp_state);
568                 if (!NT_STATUS_IS_OK(status)) {
569                         goto out;
570                 }
571
572                 status = auth_ntlmssp_update(session->auth_ntlmssp_state,
573                                              secblob_in,
574                                              &chal_out);
575         }
576
577         if (!NT_STATUS_IS_OK(status) &&
578                         !NT_STATUS_EQUAL(status,
579                                 NT_STATUS_MORE_PROCESSING_REQUIRED)) {
580                 goto out;
581         }
582
583         secblob_out = spnego_gen_auth_response(&chal_out,
584                                                 status,
585                                                 OID_NTLMSSP);
586         *out_security_buffer = data_blob_talloc(smb2req,
587                                                 secblob_out.data,
588                                                 secblob_out.length);
589         if (secblob_out.data && out_security_buffer->data == NULL) {
590                 status = NT_STATUS_NO_MEMORY;
591                 goto out;
592         }
593         *out_session_id = session->vuid;
594
595   out:
596
597         data_blob_free(&secblob_in);
598         data_blob_free(&secblob_out);
599         data_blob_free(&chal_out);
600         SAFE_FREE(kerb_mech);
601         if (!NT_STATUS_IS_OK(status) &&
602                         !NT_STATUS_EQUAL(status,
603                                 NT_STATUS_MORE_PROCESSING_REQUIRED)) {
604                 auth_ntlmssp_end(&session->auth_ntlmssp_state);
605                 TALLOC_FREE(session);
606         }
607         return status;
608 }
609
610 static NTSTATUS smbd_smb2_common_ntlmssp_auth_return(struct smbd_smb2_session *session,
611                                         struct smbd_smb2_request *smb2req,
612                                         uint8_t in_security_mode,
613                                         DATA_BLOB in_security_buffer,
614                                         uint16_t *out_session_flags,
615                                         uint64_t *out_session_id)
616 {
617         fstring tmp;
618         session->server_info = auth_ntlmssp_server_info(session, session->auth_ntlmssp_state);
619         if (!session->server_info) {
620                 auth_ntlmssp_end(&session->auth_ntlmssp_state);
621                 TALLOC_FREE(session);
622                 return NT_STATUS_NO_MEMORY;
623         }
624
625         if ((in_security_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED) ||
626             lp_server_signing() == Required) {
627                 session->do_signing = true;
628         }
629
630         if (session->server_info->guest) {
631                 /* we map anonymous to guest internally */
632                 *out_session_flags |= SMB2_SESSION_FLAG_IS_GUEST;
633                 *out_session_flags |= SMB2_SESSION_FLAG_IS_NULL;
634                 /* force no signing */
635                 session->do_signing = false;
636         }
637
638         session->session_key = session->server_info->user_session_key;
639
640         session->compat_vuser = talloc_zero(session, user_struct);
641         if (session->compat_vuser == NULL) {
642                 auth_ntlmssp_end(&session->auth_ntlmssp_state);
643                 TALLOC_FREE(session);
644                 return NT_STATUS_NO_MEMORY;
645         }
646         session->compat_vuser->auth_ntlmssp_state = session->auth_ntlmssp_state;
647         session->compat_vuser->homes_snum = -1;
648         session->compat_vuser->server_info = session->server_info;
649         session->compat_vuser->session_keystr = NULL;
650         session->compat_vuser->vuid = session->vuid;
651         DLIST_ADD(session->sconn->smb1.sessions.validated_users, session->compat_vuser);
652
653         /* This is a potentially untrusted username */
654         alpha_strcpy(tmp,
655                      auth_ntlmssp_get_username(session->auth_ntlmssp_state),
656                      ". _-$",
657                      sizeof(tmp));
658         session->server_info->sanitized_username = talloc_strdup(
659                 session->server_info, tmp);
660
661         if (!session->compat_vuser->server_info->guest) {
662                 session->compat_vuser->homes_snum =
663                         register_homes_share(session->server_info->unix_name);
664         }
665
666         if (!session_claim(sconn_server_id(session->sconn),
667                            session->compat_vuser)) {
668                 DEBUG(1, ("smb2: Failed to claim session "
669                         "for vuid=%d\n",
670                         session->compat_vuser->vuid));
671                 auth_ntlmssp_end(&session->auth_ntlmssp_state);
672                 TALLOC_FREE(session);
673                 return NT_STATUS_LOGON_FAILURE;
674         }
675
676
677         session->status = NT_STATUS_OK;
678
679         /*
680          * we attach the session to the request
681          * so that the response can be signed
682          */
683         smb2req->session = session;
684         if (session->do_signing) {
685                 smb2req->do_signing = true;
686         }
687
688         global_client_caps |= (CAP_LEVEL_II_OPLOCKS|CAP_STATUS32);
689
690         *out_session_id = session->vuid;
691
692         return NT_STATUS_OK;
693 }
694
695 static NTSTATUS smbd_smb2_spnego_auth(struct smbd_smb2_session *session,
696                                         struct smbd_smb2_request *smb2req,
697                                         uint8_t in_security_mode,
698                                         DATA_BLOB in_security_buffer,
699                                         uint16_t *out_session_flags,
700                                         DATA_BLOB *out_security_buffer,
701                                         uint64_t *out_session_id)
702 {
703         DATA_BLOB auth = data_blob_null;
704         DATA_BLOB auth_out = data_blob_null;
705         DATA_BLOB secblob_out = data_blob_null;
706         NTSTATUS status;
707
708         if (!spnego_parse_auth(in_security_buffer, &auth)) {
709                 TALLOC_FREE(session);
710                 return NT_STATUS_LOGON_FAILURE;
711         }
712
713         if (auth.data[0] == ASN1_APPLICATION(0)) {
714                 /* Might be a second negTokenTarg packet */
715                 DATA_BLOB secblob_in = data_blob_null;
716                 char *kerb_mech = NULL;
717
718                 status = parse_spnego_mechanisms(in_security_buffer,
719                                 &secblob_in, &kerb_mech);
720                 if (!NT_STATUS_IS_OK(status)) {
721                         TALLOC_FREE(session);
722                         return status;
723                 }
724
725 #ifdef HAVE_KRB5
726                 if (kerb_mech && ((lp_security()==SEC_ADS) ||
727                                         USE_KERBEROS_KEYTAB) ) {
728                         status = smbd_smb2_session_setup_krb5(session,
729                                         smb2req,
730                                         in_security_mode,
731                                         &secblob_in,
732                                         kerb_mech,
733                                         out_session_flags,
734                                         out_security_buffer,
735                                         out_session_id);
736
737                         data_blob_free(&secblob_in);
738                         SAFE_FREE(kerb_mech);
739                         if (!NT_STATUS_IS_OK(status)) {
740                                 TALLOC_FREE(session);
741                         }
742                         return status;
743                 }
744 #endif
745
746                 /* Can't blunder into NTLMSSP auth if we have
747                  * a krb5 ticket. */
748
749                 if (kerb_mech) {
750                         DEBUG(3,("smb2: network "
751                                 "misconfiguration, client sent us a "
752                                 "krb5 ticket and kerberos security "
753                                 "not enabled\n"));
754                         TALLOC_FREE(session);
755                         data_blob_free(&secblob_in);
756                         SAFE_FREE(kerb_mech);
757                         return NT_STATUS_LOGON_FAILURE;
758                 }
759
760                 data_blob_free(&secblob_in);
761         }
762
763         if (session->auth_ntlmssp_state == NULL) {
764                 status = auth_ntlmssp_start(&session->auth_ntlmssp_state);
765                 if (!NT_STATUS_IS_OK(status)) {
766                         data_blob_free(&auth);
767                         TALLOC_FREE(session);
768                         return status;
769                 }
770         }
771
772         status = auth_ntlmssp_update(session->auth_ntlmssp_state,
773                                      auth,
774                                      &auth_out);
775         if (!NT_STATUS_IS_OK(status) &&
776                         !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
777                 auth_ntlmssp_end(&session->auth_ntlmssp_state);
778                 data_blob_free(&auth);
779                 TALLOC_FREE(session);
780                 return status;
781         }
782
783         data_blob_free(&auth);
784
785         secblob_out = spnego_gen_auth_response(&auth_out,
786                                status, NULL);
787
788         *out_security_buffer = data_blob_talloc(smb2req,
789                                                 secblob_out.data,
790                                                 secblob_out.length);
791         if (secblob_out.data && out_security_buffer->data == NULL) {
792                 auth_ntlmssp_end(&session->auth_ntlmssp_state);
793                 TALLOC_FREE(session);
794                 return NT_STATUS_NO_MEMORY;
795         }
796
797         *out_session_id = session->vuid;
798
799         if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
800                 return NT_STATUS_MORE_PROCESSING_REQUIRED;
801         }
802
803         /* We're done - claim the session. */
804         return smbd_smb2_common_ntlmssp_auth_return(session,
805                                                 smb2req,
806                                                 in_security_mode,
807                                                 in_security_buffer,
808                                                 out_session_flags,
809                                                 out_session_id);
810 }
811
812 static NTSTATUS smbd_smb2_raw_ntlmssp_auth(struct smbd_smb2_session *session,
813                                         struct smbd_smb2_request *smb2req,
814                                         uint8_t in_security_mode,
815                                         DATA_BLOB in_security_buffer,
816                                         uint16_t *out_session_flags,
817                                         DATA_BLOB *out_security_buffer,
818                                         uint64_t *out_session_id)
819 {
820         NTSTATUS status;
821         DATA_BLOB secblob_out = data_blob_null;
822
823         if (session->auth_ntlmssp_state == NULL) {
824                 status = auth_ntlmssp_start(&session->auth_ntlmssp_state);
825                 if (!NT_STATUS_IS_OK(status)) {
826                         TALLOC_FREE(session);
827                         return status;
828                 }
829         }
830
831         /* RAW NTLMSSP */
832         status = auth_ntlmssp_update(session->auth_ntlmssp_state,
833                                      in_security_buffer,
834                                      &secblob_out);
835
836         if (NT_STATUS_IS_OK(status) ||
837                         NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
838                 *out_security_buffer = data_blob_talloc(smb2req,
839                                                 secblob_out.data,
840                                                 secblob_out.length);
841                 if (secblob_out.data && out_security_buffer->data == NULL) {
842                         auth_ntlmssp_end(&session->auth_ntlmssp_state);
843                         TALLOC_FREE(session);
844                         return NT_STATUS_NO_MEMORY;
845                 }
846         }
847
848         if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
849                 *out_session_id = session->vuid;
850                 return status;
851         }
852         if (!NT_STATUS_IS_OK(status)) {
853                 auth_ntlmssp_end(&session->auth_ntlmssp_state);
854                 TALLOC_FREE(session);
855                 return status;
856         }
857         *out_session_id = session->vuid;
858
859         return smbd_smb2_common_ntlmssp_auth_return(session,
860                                                 smb2req,
861                                                 in_security_mode,
862                                                 in_security_buffer,
863                                                 out_session_flags,
864                                                 out_session_id);
865 }
866
867 static NTSTATUS smbd_smb2_session_setup(struct smbd_smb2_request *smb2req,
868                                         uint64_t in_session_id,
869                                         uint8_t in_security_mode,
870                                         DATA_BLOB in_security_buffer,
871                                         uint16_t *out_session_flags,
872                                         DATA_BLOB *out_security_buffer,
873                                         uint64_t *out_session_id)
874 {
875         struct smbd_smb2_session *session;
876
877         *out_session_flags = 0;
878         *out_session_id = 0;
879
880         if (in_session_id == 0) {
881                 int id;
882
883                 /* create a new session */
884                 session = talloc_zero(smb2req->sconn, struct smbd_smb2_session);
885                 if (session == NULL) {
886                         return NT_STATUS_NO_MEMORY;
887                 }
888                 session->status = NT_STATUS_MORE_PROCESSING_REQUIRED;
889                 id = idr_get_new_random(smb2req->sconn->smb2.sessions.idtree,
890                                         session,
891                                         smb2req->sconn->smb2.sessions.limit);
892                 if (id == -1) {
893                         return NT_STATUS_INSUFFICIENT_RESOURCES;
894                 }
895                 session->vuid = id;
896
897                 session->tcons.idtree = idr_init(session);
898                 if (session->tcons.idtree == NULL) {
899                         return NT_STATUS_NO_MEMORY;
900                 }
901                 session->tcons.limit = 0x0000FFFE;
902                 session->tcons.list = NULL;
903
904                 DLIST_ADD_END(smb2req->sconn->smb2.sessions.list, session,
905                               struct smbd_smb2_session *);
906                 session->sconn = smb2req->sconn;
907                 talloc_set_destructor(session, smbd_smb2_session_destructor);
908         } else {
909                 void *p;
910
911                 /* lookup an existing session */
912                 p = idr_find(smb2req->sconn->smb2.sessions.idtree, in_session_id);
913                 if (p == NULL) {
914                         return NT_STATUS_USER_SESSION_DELETED;
915                 }
916                 session = talloc_get_type_abort(p, struct smbd_smb2_session);
917         }
918
919         if (NT_STATUS_IS_OK(session->status)) {
920                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
921         }
922
923         if (in_security_buffer.data[0] == ASN1_APPLICATION(0)) {
924                 return smbd_smb2_spnego_negotiate(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 (in_security_buffer.data[0] == ASN1_CONTEXT(1)) {
932                 return smbd_smb2_spnego_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         } else if (strncmp((char *)(in_security_buffer.data), "NTLMSSP", 7) == 0) {
940                 return smbd_smb2_raw_ntlmssp_auth(session,
941                                                 smb2req,
942                                                 in_security_mode,
943                                                 in_security_buffer,
944                                                 out_session_flags,
945                                                 out_security_buffer,
946                                                 out_session_id);
947         }
948
949         /* Unknown packet type. */
950         DEBUG(1,("Unknown packet type %u in smb2 sessionsetup\n",
951                 (unsigned int)in_security_buffer.data[0] ));
952         auth_ntlmssp_end(&session->auth_ntlmssp_state);
953         TALLOC_FREE(session);
954         return NT_STATUS_LOGON_FAILURE;
955 }
956
957 NTSTATUS smbd_smb2_request_check_session(struct smbd_smb2_request *req)
958 {
959         const uint8_t *inhdr;
960         const uint8_t *outhdr;
961         int i = req->current_idx;
962         uint64_t in_session_id;
963         void *p;
964         struct smbd_smb2_session *session;
965         bool chained_fixup = false;
966
967         inhdr = (const uint8_t *)req->in.vector[i+0].iov_base;
968
969         in_session_id = BVAL(inhdr, SMB2_HDR_SESSION_ID);
970
971         if (in_session_id == (0xFFFFFFFFFFFFFFFFLL)) {
972                 if (req->async) {
973                         /*
974                          * async request - fill in session_id from
975                          * already setup request out.vector[].iov_base.
976                          */
977                         outhdr = (const uint8_t *)req->out.vector[i].iov_base;
978                         in_session_id = BVAL(outhdr, SMB2_HDR_SESSION_ID);
979                 } else if (i > 2) {
980                         /*
981                          * Chained request - fill in session_id from
982                          * the previous request out.vector[].iov_base.
983                          */
984                         outhdr = (const uint8_t *)req->out.vector[i-3].iov_base;
985                         in_session_id = BVAL(outhdr, SMB2_HDR_SESSION_ID);
986                         chained_fixup = true;
987                 }
988         }
989
990         /* lookup an existing session */
991         p = idr_find(req->sconn->smb2.sessions.idtree, in_session_id);
992         if (p == NULL) {
993                 return NT_STATUS_USER_SESSION_DELETED;
994         }
995         session = talloc_get_type_abort(p, struct smbd_smb2_session);
996
997         if (!NT_STATUS_IS_OK(session->status)) {
998                 return NT_STATUS_ACCESS_DENIED;
999         }
1000
1001         set_current_user_info(session->server_info->sanitized_username,
1002                               session->server_info->unix_name,
1003                               session->server_info->info3->base.domain.string);
1004
1005         req->session = session;
1006
1007         if (chained_fixup) {
1008                 /* Fix up our own outhdr. */
1009                 outhdr = (const uint8_t *)req->out.vector[i].iov_base;
1010                 SBVAL(outhdr, SMB2_HDR_SESSION_ID, in_session_id);
1011         }
1012         return NT_STATUS_OK;
1013 }
1014
1015 NTSTATUS smbd_smb2_request_process_logoff(struct smbd_smb2_request *req)
1016 {
1017         const uint8_t *inbody;
1018         int i = req->current_idx;
1019         DATA_BLOB outbody;
1020         size_t expected_body_size = 0x04;
1021         size_t body_size;
1022
1023         if (req->in.vector[i+1].iov_len != (expected_body_size & 0xFFFFFFFE)) {
1024                 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
1025         }
1026
1027         inbody = (const uint8_t *)req->in.vector[i+1].iov_base;
1028
1029         body_size = SVAL(inbody, 0x00);
1030         if (body_size != expected_body_size) {
1031                 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
1032         }
1033
1034         /*
1035          * TODO: cancel all outstanding requests on the session
1036          *       and delete all tree connections.
1037          */
1038         smbd_smb2_session_destructor(req->session);
1039         /*
1040          * we may need to sign the response, so we need to keep
1041          * the session until the response is sent to the wire.
1042          */
1043         talloc_steal(req, req->session);
1044
1045         outbody = data_blob_talloc(req->out.vector, NULL, 0x04);
1046         if (outbody.data == NULL) {
1047                 return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
1048         }
1049
1050         SSVAL(outbody.data, 0x00, 0x04);        /* struct size */
1051         SSVAL(outbody.data, 0x02, 0);           /* reserved */
1052
1053         return smbd_smb2_request_done(req, outbody, NULL);
1054 }