]> git.samba.org - amitay/samba.git/blob - source3/smbd/smb2_sesssetup.c
Allow us to cope correctly with NT_STATUS_MORE_PROCESSING_REQUIRED when downgrading...
[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(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         session->server_info = auth_ntlmssp_server_info(session, session->auth_ntlmssp_state);
618         if (!session->server_info) {
619                 auth_ntlmssp_end(&session->auth_ntlmssp_state);
620                 TALLOC_FREE(session);
621                 return NT_STATUS_NO_MEMORY;
622         }
623
624         if ((in_security_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED) ||
625             lp_server_signing() == Required) {
626                 session->do_signing = true;
627         }
628
629         if (session->server_info->guest) {
630                 /* we map anonymous to guest internally */
631                 *out_session_flags |= SMB2_SESSION_FLAG_IS_GUEST;
632                 *out_session_flags |= SMB2_SESSION_FLAG_IS_NULL;
633                 /* force no signing */
634                 session->do_signing = false;
635         }
636
637         session->session_key = session->server_info->user_session_key;
638
639         session->compat_vuser = talloc_zero(session, user_struct);
640         if (session->compat_vuser == NULL) {
641                 auth_ntlmssp_end(&session->auth_ntlmssp_state);
642                 TALLOC_FREE(session);
643                 return NT_STATUS_NO_MEMORY;
644         }
645         session->compat_vuser->auth_ntlmssp_state = session->auth_ntlmssp_state;
646         session->compat_vuser->homes_snum = -1;
647         session->compat_vuser->server_info = session->server_info;
648         session->compat_vuser->session_keystr = NULL;
649         session->compat_vuser->vuid = session->vuid;
650         DLIST_ADD(session->sconn->smb1.sessions.validated_users, session->compat_vuser);
651
652         /* This is a potentially untrusted username */
653         alpha_strcpy(tmp,
654                      auth_ntlmssp_get_username(session->auth_ntlmssp_state),
655                      ". _-$",
656                      sizeof(tmp));
657         session->server_info->sanitized_username = talloc_strdup(
658                 session->server_info, tmp);
659
660         if (!session->compat_vuser->server_info->guest) {
661                 session->compat_vuser->homes_snum =
662                         register_homes_share(session->server_info->unix_name);
663         }
664
665         if (!session_claim(session->compat_vuser)) {
666                 DEBUG(1, ("smb2: Failed to claim session "
667                         "for vuid=%d\n",
668                         session->compat_vuser->vuid));
669                 auth_ntlmssp_end(&session->auth_ntlmssp_state);
670                 TALLOC_FREE(session);
671                 return NT_STATUS_LOGON_FAILURE;
672         }
673
674
675         session->status = NT_STATUS_OK;
676
677         /*
678          * we attach the session to the request
679          * so that the response can be signed
680          */
681         smb2req->session = session;
682         if (session->do_signing) {
683                 smb2req->do_signing = true;
684         }
685
686         global_client_caps |= (CAP_LEVEL_II_OPLOCKS|CAP_STATUS32);
687
688         *out_session_id = session->vuid;
689
690         return NT_STATUS_OK;
691 }
692
693 static NTSTATUS smbd_smb2_spnego_auth(struct smbd_smb2_session *session,
694                                         struct smbd_smb2_request *smb2req,
695                                         uint8_t in_security_mode,
696                                         DATA_BLOB in_security_buffer,
697                                         uint16_t *out_session_flags,
698                                         DATA_BLOB *out_security_buffer,
699                                         uint64_t *out_session_id)
700 {
701         DATA_BLOB auth = data_blob_null;
702         DATA_BLOB auth_out = data_blob_null;
703         DATA_BLOB secblob_out = data_blob_null;
704         NTSTATUS status;
705
706         if (!spnego_parse_auth(in_security_buffer, &auth)) {
707                 TALLOC_FREE(session);
708                 return NT_STATUS_LOGON_FAILURE;
709         }
710
711         if (auth.data[0] == ASN1_APPLICATION(0)) {
712                 /* Might be a second negTokenTarg packet */
713                 DATA_BLOB secblob_in = data_blob_null;
714                 char *kerb_mech = NULL;
715
716                 status = parse_spnego_mechanisms(in_security_buffer,
717                                 &secblob_in, &kerb_mech);
718                 if (!NT_STATUS_IS_OK(status)) {
719                         TALLOC_FREE(session);
720                         return status;
721                 }
722
723 #ifdef HAVE_KRB5
724                 if (kerb_mech && ((lp_security()==SEC_ADS) ||
725                                         USE_KERBEROS_KEYTAB) ) {
726                         status = smbd_smb2_session_setup_krb5(session,
727                                         smb2req,
728                                         in_security_mode,
729                                         &secblob_in,
730                                         kerb_mech,
731                                         out_session_flags,
732                                         out_security_buffer,
733                                         out_session_id);
734
735                         data_blob_free(&secblob_in);
736                         SAFE_FREE(kerb_mech);
737                         if (!NT_STATUS_IS_OK(status)) {
738                                 TALLOC_FREE(session);
739                         }
740                         return status;
741                 }
742 #endif
743
744                 /* Can't blunder into NTLMSSP auth if we have
745                  * a krb5 ticket. */
746
747                 if (kerb_mech) {
748                         DEBUG(3,("smb2: network "
749                                 "misconfiguration, client sent us a "
750                                 "krb5 ticket and kerberos security "
751                                 "not enabled\n"));
752                         TALLOC_FREE(session);
753                         data_blob_free(&secblob_in);
754                         SAFE_FREE(kerb_mech);
755                         return NT_STATUS_LOGON_FAILURE;
756                 }
757
758                 data_blob_free(&secblob_in);
759         }
760
761         if (session->auth_ntlmssp_state == NULL) {
762                 status = auth_ntlmssp_start(&session->auth_ntlmssp_state);
763                 if (!NT_STATUS_IS_OK(status)) {
764                         data_blob_free(&auth);
765                         TALLOC_FREE(session);
766                         return status;
767                 }
768         }
769
770         status = auth_ntlmssp_update(session->auth_ntlmssp_state,
771                                      auth,
772                                      &auth_out);
773         if (!NT_STATUS_IS_OK(status) &&
774                         !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
775                 auth_ntlmssp_end(&session->auth_ntlmssp_state);
776                 data_blob_free(&auth);
777                 TALLOC_FREE(session);
778                 return status;
779         }
780
781         data_blob_free(&auth);
782
783         secblob_out = spnego_gen_auth_response(&auth_out,
784                                status, NULL);
785
786         *out_security_buffer = data_blob_talloc(smb2req,
787                                                 secblob_out.data,
788                                                 secblob_out.length);
789         if (secblob_out.data && out_security_buffer->data == NULL) {
790                 auth_ntlmssp_end(&session->auth_ntlmssp_state);
791                 TALLOC_FREE(session);
792                 return NT_STATUS_NO_MEMORY;
793         }
794
795         *out_session_id = session->vuid;
796
797         if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
798                 return NT_STATUS_MORE_PROCESSING_REQUIRED;
799         }
800
801         /* We're done - claim the session. */
802         return smbd_smb2_common_ntlmssp_auth_return(session,
803                                                 smb2req,
804                                                 in_security_mode,
805                                                 in_security_buffer,
806                                                 out_session_flags,
807                                                 out_session_id);
808 }
809
810 static NTSTATUS smbd_smb2_raw_ntlmssp_auth(struct smbd_smb2_session *session,
811                                         struct smbd_smb2_request *smb2req,
812                                         uint8_t in_security_mode,
813                                         DATA_BLOB in_security_buffer,
814                                         uint16_t *out_session_flags,
815                                         DATA_BLOB *out_security_buffer,
816                                         uint64_t *out_session_id)
817 {
818         NTSTATUS status;
819         DATA_BLOB secblob_out = data_blob_null;
820
821         if (session->auth_ntlmssp_state == NULL) {
822                 status = auth_ntlmssp_start(&session->auth_ntlmssp_state);
823                 if (!NT_STATUS_IS_OK(status)) {
824                         TALLOC_FREE(session);
825                         return status;
826                 }
827         }
828
829         /* RAW NTLMSSP */
830         status = auth_ntlmssp_update(session->auth_ntlmssp_state,
831                                      in_security_buffer,
832                                      &secblob_out);
833
834         if (NT_STATUS_IS_OK(status) ||
835                         NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
836                 *out_security_buffer = data_blob_talloc(smb2req,
837                                                 secblob_out.data,
838                                                 secblob_out.length);
839                 if (secblob_out.data && out_security_buffer->data == NULL) {
840                         auth_ntlmssp_end(&session->auth_ntlmssp_state);
841                         TALLOC_FREE(session);
842                         return NT_STATUS_NO_MEMORY;
843                 }
844         }
845
846         if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
847                 *out_session_id = session->vuid;
848                 return status;
849         }
850         if (!NT_STATUS_IS_OK(status)) {
851                 auth_ntlmssp_end(&session->auth_ntlmssp_state);
852                 TALLOC_FREE(session);
853                 return status;
854         }
855         *out_session_id = session->vuid;
856
857         return smbd_smb2_common_ntlmssp_auth_return(session,
858                                                 smb2req,
859                                                 in_security_mode,
860                                                 in_security_buffer,
861                                                 out_session_flags,
862                                                 out_session_id);
863 }
864
865 static NTSTATUS smbd_smb2_session_setup(struct smbd_smb2_request *smb2req,
866                                         uint64_t in_session_id,
867                                         uint8_t in_security_mode,
868                                         DATA_BLOB in_security_buffer,
869                                         uint16_t *out_session_flags,
870                                         DATA_BLOB *out_security_buffer,
871                                         uint64_t *out_session_id)
872 {
873         struct smbd_smb2_session *session;
874
875         *out_session_flags = 0;
876         *out_session_id = 0;
877
878         if (in_session_id == 0) {
879                 int id;
880
881                 /* create a new session */
882                 session = talloc_zero(smb2req->sconn, struct smbd_smb2_session);
883                 if (session == NULL) {
884                         return NT_STATUS_NO_MEMORY;
885                 }
886                 session->status = NT_STATUS_MORE_PROCESSING_REQUIRED;
887                 id = idr_get_new_random(smb2req->sconn->smb2.sessions.idtree,
888                                         session,
889                                         smb2req->sconn->smb2.sessions.limit);
890                 if (id == -1) {
891                         return NT_STATUS_INSUFFICIENT_RESOURCES;
892                 }
893                 session->vuid = id;
894
895                 session->tcons.idtree = idr_init(session);
896                 if (session->tcons.idtree == NULL) {
897                         return NT_STATUS_NO_MEMORY;
898                 }
899                 session->tcons.limit = 0x0000FFFE;
900                 session->tcons.list = NULL;
901
902                 DLIST_ADD_END(smb2req->sconn->smb2.sessions.list, session,
903                               struct smbd_smb2_session *);
904                 session->sconn = smb2req->sconn;
905                 talloc_set_destructor(session, smbd_smb2_session_destructor);
906         } else {
907                 void *p;
908
909                 /* lookup an existing session */
910                 p = idr_find(smb2req->sconn->smb2.sessions.idtree, in_session_id);
911                 if (p == NULL) {
912                         return NT_STATUS_USER_SESSION_DELETED;
913                 }
914                 session = talloc_get_type_abort(p, struct smbd_smb2_session);
915         }
916
917         if (NT_STATUS_IS_OK(session->status)) {
918                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
919         }
920
921         if (in_security_buffer.data[0] == ASN1_APPLICATION(0)) {
922                 return smbd_smb2_spnego_negotiate(session,
923                                                 smb2req,
924                                                 in_security_mode,
925                                                 in_security_buffer,
926                                                 out_session_flags,
927                                                 out_security_buffer,
928                                                 out_session_id);
929         } else if (in_security_buffer.data[0] == ASN1_CONTEXT(1)) {
930                 return smbd_smb2_spnego_auth(session,
931                                                 smb2req,
932                                                 in_security_mode,
933                                                 in_security_buffer,
934                                                 out_session_flags,
935                                                 out_security_buffer,
936                                                 out_session_id);
937         } else if (strncmp((char *)(in_security_buffer.data), "NTLMSSP", 7) == 0) {
938                 return smbd_smb2_raw_ntlmssp_auth(session,
939                                                 smb2req,
940                                                 in_security_mode,
941                                                 in_security_buffer,
942                                                 out_session_flags,
943                                                 out_security_buffer,
944                                                 out_session_id);
945         }
946
947         /* Unknown packet type. */
948         DEBUG(1,("Unknown packet type %u in smb2 sessionsetup\n",
949                 (unsigned int)in_security_buffer.data[0] ));
950         auth_ntlmssp_end(&session->auth_ntlmssp_state);
951         TALLOC_FREE(session);
952         return NT_STATUS_LOGON_FAILURE;
953 }
954
955 NTSTATUS smbd_smb2_request_check_session(struct smbd_smb2_request *req)
956 {
957         const uint8_t *inhdr;
958         const uint8_t *outhdr;
959         int i = req->current_idx;
960         uint64_t in_session_id;
961         void *p;
962         struct smbd_smb2_session *session;
963         bool chained_fixup = false;
964
965         inhdr = (const uint8_t *)req->in.vector[i+0].iov_base;
966
967         in_session_id = BVAL(inhdr, SMB2_HDR_SESSION_ID);
968
969         if (in_session_id == (0xFFFFFFFFFFFFFFFFLL)) {
970                 if (req->async) {
971                         /*
972                          * async request - fill in session_id from
973                          * already setup request out.vector[].iov_base.
974                          */
975                         outhdr = (const uint8_t *)req->out.vector[i].iov_base;
976                         in_session_id = BVAL(outhdr, SMB2_HDR_SESSION_ID);
977                 } else if (i > 2) {
978                         /*
979                          * Chained request - fill in session_id from
980                          * the previous request out.vector[].iov_base.
981                          */
982                         outhdr = (const uint8_t *)req->out.vector[i-3].iov_base;
983                         in_session_id = BVAL(outhdr, SMB2_HDR_SESSION_ID);
984                         chained_fixup = true;
985                 }
986         }
987
988         /* lookup an existing session */
989         p = idr_find(req->sconn->smb2.sessions.idtree, in_session_id);
990         if (p == NULL) {
991                 return NT_STATUS_USER_SESSION_DELETED;
992         }
993         session = talloc_get_type_abort(p, struct smbd_smb2_session);
994
995         if (!NT_STATUS_IS_OK(session->status)) {
996                 return NT_STATUS_ACCESS_DENIED;
997         }
998
999         set_current_user_info(session->server_info->sanitized_username,
1000                               session->server_info->unix_name,
1001                               session->server_info->info3->base.domain.string);
1002
1003         req->session = session;
1004
1005         if (chained_fixup) {
1006                 /* Fix up our own outhdr. */
1007                 outhdr = (const uint8_t *)req->out.vector[i].iov_base;
1008                 SBVAL(outhdr, SMB2_HDR_SESSION_ID, in_session_id);
1009         }
1010         return NT_STATUS_OK;
1011 }
1012
1013 NTSTATUS smbd_smb2_request_process_logoff(struct smbd_smb2_request *req)
1014 {
1015         const uint8_t *inbody;
1016         int i = req->current_idx;
1017         DATA_BLOB outbody;
1018         size_t expected_body_size = 0x04;
1019         size_t body_size;
1020
1021         if (req->in.vector[i+1].iov_len != (expected_body_size & 0xFFFFFFFE)) {
1022                 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
1023         }
1024
1025         inbody = (const uint8_t *)req->in.vector[i+1].iov_base;
1026
1027         body_size = SVAL(inbody, 0x00);
1028         if (body_size != expected_body_size) {
1029                 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
1030         }
1031
1032         /*
1033          * TODO: cancel all outstanding requests on the session
1034          *       and delete all tree connections.
1035          */
1036         smbd_smb2_session_destructor(req->session);
1037         /*
1038          * we may need to sign the response, so we need to keep
1039          * the session until the response is sent to the wire.
1040          */
1041         talloc_steal(req, req->session);
1042
1043         outbody = data_blob_talloc(req->out.vector, NULL, 0x04);
1044         if (outbody.data == NULL) {
1045                 return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
1046         }
1047
1048         SSVAL(outbody.data, 0x00, 0x04);        /* struct size */
1049         SSVAL(outbody.data, 0x02, 0);           /* reserved */
1050
1051         return smbd_smb2_request_done(req, outbody, NULL);
1052 }