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