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