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