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