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