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