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