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