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