s3:smbd: the spnego session setup don't need to copy the in blob
[Samba/gbeck.git] / source3 / smbd / sesssetup.c
blobd6f45d9c345b6bcc28c9d22f18ae4aaca5c85f0d
1 /*
2 Unix SMB/CIFS implementation.
3 handle SMBsessionsetup
4 Copyright (C) Andrew Tridgell 1998-2001
5 Copyright (C) Andrew Bartlett 2001
6 Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2002
7 Copyright (C) Luke Howard 2003
8 Copyright (C) Volker Lendecke 2007
9 Copyright (C) Jeremy Allison 2007
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 3 of the License, or
14 (at your option) any later version.
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program. If not, see <http://www.gnu.org/licenses/>.
25 #include "includes.h"
26 #include "../lib/tsocket/tsocket.h"
27 #include "smbd/smbd.h"
28 #include "smbd/globals.h"
29 #include "../libcli/auth/spnego.h"
30 #include "../auth/ntlmssp/ntlmssp.h"
31 #include "../librpc/gen_ndr/krb5pac.h"
32 #include "libads/kerberos_proto.h"
33 #include "../lib/util/asn1.h"
34 #include "auth.h"
35 #include "messages.h"
36 #include "smbprofile.h"
37 #include "../libcli/security/security.h"
38 #include "auth/gensec/gensec.h"
40 /****************************************************************************
41 Add the standard 'Samba' signature to the end of the session setup.
42 ****************************************************************************/
44 static int push_signature(uint8 **outbuf)
46 char *lanman;
47 int result, tmp;
49 result = 0;
51 tmp = message_push_string(outbuf, "Unix", STR_TERMINATE);
53 if (tmp == -1) return -1;
54 result += tmp;
56 if (asprintf(&lanman, "Samba %s", samba_version_string()) != -1) {
57 tmp = message_push_string(outbuf, lanman, STR_TERMINATE);
58 SAFE_FREE(lanman);
60 else {
61 tmp = message_push_string(outbuf, "Samba", STR_TERMINATE);
64 if (tmp == -1) return -1;
65 result += tmp;
67 tmp = message_push_string(outbuf, lp_workgroup(), STR_TERMINATE);
69 if (tmp == -1) return -1;
70 result += tmp;
72 return result;
75 /****************************************************************************
76 Send a security blob via a session setup reply.
77 ****************************************************************************/
79 static void reply_sesssetup_blob(struct smb_request *req,
80 DATA_BLOB blob,
81 NTSTATUS nt_status)
83 if (!NT_STATUS_IS_OK(nt_status) &&
84 !NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
85 reply_nterror(req, nt_status_squash(nt_status));
86 return;
89 nt_status = nt_status_squash(nt_status);
90 SIVAL(req->outbuf, smb_rcls, NT_STATUS_V(nt_status));
91 SSVAL(req->outbuf, smb_vwv0, 0xFF); /* no chaining possible */
92 SSVAL(req->outbuf, smb_vwv3, blob.length);
94 if ((message_push_blob(&req->outbuf, blob) == -1)
95 || (push_signature(&req->outbuf) == -1)) {
96 reply_nterror(req, NT_STATUS_NO_MEMORY);
100 /****************************************************************************
101 Do a 'guest' logon, getting back the
102 ****************************************************************************/
104 static NTSTATUS check_guest_password(const struct tsocket_address *remote_address,
105 struct auth_serversupplied_info **server_info)
107 struct auth_context *auth_context;
108 struct auth_usersupplied_info *user_info = NULL;
110 NTSTATUS nt_status;
111 static unsigned char chal[8] = { 0, };
113 DEBUG(3,("Got anonymous request\n"));
115 nt_status = make_auth_context_fixed(talloc_tos(), &auth_context, chal);
116 if (!NT_STATUS_IS_OK(nt_status)) {
117 return nt_status;
120 if (!make_user_info_guest(remote_address, &user_info)) {
121 TALLOC_FREE(auth_context);
122 return NT_STATUS_NO_MEMORY;
125 nt_status = auth_context->check_ntlm_password(auth_context,
126 user_info,
127 server_info);
128 TALLOC_FREE(auth_context);
129 free_user_info(&user_info);
130 return nt_status;
133 static void reply_spnego_generic(struct smb_request *req,
134 uint16 vuid,
135 struct gensec_security **gensec_security,
136 DATA_BLOB *blob, NTSTATUS nt_status)
138 bool do_invalidate = true;
139 struct auth_session_info *session_info = NULL;
140 struct smbd_server_connection *sconn = req->sconn;
142 if (NT_STATUS_IS_OK(nt_status)) {
143 nt_status = gensec_session_info(*gensec_security,
144 talloc_tos(),
145 &session_info);
148 reply_outbuf(req, 4, 0);
150 SSVAL(req->outbuf, smb_uid, vuid);
152 if (NT_STATUS_IS_OK(nt_status)) {
153 DATA_BLOB nullblob = data_blob_null;
155 if (!is_partial_auth_vuid(sconn, vuid)) {
156 nt_status = NT_STATUS_LOGON_FAILURE;
157 goto out;
160 /* register_existing_vuid keeps the server info */
161 if (register_existing_vuid(sconn, vuid,
162 session_info, nullblob) !=
163 vuid) {
164 /* The problem is, *gensec_security points
165 * into the vuser this will have
166 * talloc_free()'ed in
167 * register_existing_vuid() */
168 do_invalidate = false;
169 nt_status = NT_STATUS_LOGON_FAILURE;
170 goto out;
173 /* current_user_info is changed on new vuid */
174 reload_services(sconn, conn_snum_used, true);
176 SSVAL(req->outbuf, smb_vwv3, 0);
178 if (security_session_user_level(session_info, NULL) < SECURITY_USER) {
179 SSVAL(req->outbuf,smb_vwv2,1);
183 out:
185 reply_sesssetup_blob(req, *blob, nt_status);
187 /* NT_STATUS_MORE_PROCESSING_REQUIRED from our NTLMSSP code tells us,
188 and the other end, that we are not finished yet. */
190 if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
191 /* NB. This is *NOT* an error case. JRA */
192 if (do_invalidate) {
193 TALLOC_FREE(*gensec_security);
194 if (!NT_STATUS_IS_OK(nt_status)) {
195 /* Kill the intermediate vuid */
196 invalidate_vuid(sconn, vuid);
202 /****************************************************************************
203 Reply to a session setup command.
204 conn POINTER CAN BE NULL HERE !
205 ****************************************************************************/
207 static void reply_sesssetup_and_X_spnego(struct smb_request *req)
209 const uint8 *p;
210 DATA_BLOB in_blob;
211 size_t bufrem;
212 char *tmp;
213 const char *native_os;
214 const char *native_lanman;
215 const char *primary_domain;
216 const char *p2;
217 uint16 data_blob_len = SVAL(req->vwv+7, 0);
218 enum remote_arch_types ra_type = get_remote_arch();
219 int vuid = req->vuid;
220 user_struct *vuser = NULL;
221 NTSTATUS status = NT_STATUS_OK;
222 struct smbd_server_connection *sconn = req->sconn;
223 DATA_BLOB chal;
225 DEBUG(3,("Doing spnego session setup\n"));
227 if (global_client_caps == 0) {
228 global_client_caps = IVAL(req->vwv+10, 0);
230 if (!(global_client_caps & CAP_STATUS32)) {
231 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
236 p = req->buf;
238 if (data_blob_len == 0) {
239 /* an invalid request */
240 reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
241 return;
244 bufrem = smbreq_bufrem(req, p);
245 /* pull the spnego blob */
246 in_blob = data_blob_const(p, MIN(bufrem, data_blob_len));
248 #if 0
249 file_save("negotiate.dat", in_blob.data, in_blob.length);
250 #endif
252 p2 = (const char *)req->buf + in_blob.length;
254 p2 += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p2,
255 STR_TERMINATE);
256 native_os = tmp ? tmp : "";
258 p2 += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p2,
259 STR_TERMINATE);
260 native_lanman = tmp ? tmp : "";
262 p2 += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p2,
263 STR_TERMINATE);
264 primary_domain = tmp ? tmp : "";
266 DEBUG(3,("NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n",
267 native_os, native_lanman, primary_domain));
269 if ( ra_type == RA_WIN2K ) {
270 /* Vista sets neither the OS or lanman strings */
272 if ( !strlen(native_os) && !strlen(native_lanman) )
273 set_remote_arch(RA_VISTA);
275 /* Windows 2003 doesn't set the native lanman string,
276 but does set primary domain which is a bug I think */
278 if ( !strlen(native_lanman) ) {
279 ra_lanman_string( primary_domain );
280 } else {
281 ra_lanman_string( native_lanman );
283 } else if ( ra_type == RA_VISTA ) {
284 if ( strncmp(native_os, "Mac OS X", 8) == 0 ) {
285 set_remote_arch(RA_OSX);
289 /* Do we have a valid vuid now ? */
290 if (!is_partial_auth_vuid(sconn, vuid)) {
291 /* No, start a new authentication setup. */
292 vuid = register_initial_vuid(sconn);
293 if (vuid == UID_FIELD_INVALID) {
294 reply_nterror(req, nt_status_squash(
295 NT_STATUS_INVALID_PARAMETER));
296 return;
300 vuser = get_partial_auth_user_struct(sconn, vuid);
301 /* This MUST be valid. */
302 if (!vuser) {
303 smb_panic("reply_sesssetup_and_X_spnego: invalid vuid.");
306 if (!vuser->gensec_security) {
307 status = auth_generic_prepare(vuser, sconn->remote_address,
308 &vuser->gensec_security);
309 if (!NT_STATUS_IS_OK(status)) {
310 /* Kill the intermediate vuid */
311 invalidate_vuid(sconn, vuid);
312 reply_nterror(req, nt_status_squash(status));
313 return;
316 gensec_want_feature(vuser->gensec_security, GENSEC_FEATURE_SESSION_KEY);
317 gensec_want_feature(vuser->gensec_security, GENSEC_FEATURE_UNIX_TOKEN);
319 if (sconn->use_gensec_hook) {
320 status = gensec_start_mech_by_oid(vuser->gensec_security, GENSEC_OID_SPNEGO);
321 } else {
322 status = gensec_start_mech_by_oid(vuser->gensec_security, GENSEC_OID_NTLMSSP);
324 if (!NT_STATUS_IS_OK(status)) {
325 /* Kill the intermediate vuid */
326 invalidate_vuid(sconn, vuid);
327 reply_nterror(req, nt_status_squash(status));
328 return;
332 status = gensec_update(vuser->gensec_security,
333 talloc_tos(), NULL,
334 in_blob, &chal);
336 reply_spnego_generic(req, vuid,
337 &vuser->gensec_security,
338 &chal, status);
339 data_blob_free(&chal);
340 return;
343 /****************************************************************************
344 On new VC == 0, shutdown *all* old connections and users.
345 It seems that only NT4.x does this. At W2K and above (XP etc.).
346 a new session setup with VC==0 is ignored.
347 ****************************************************************************/
349 struct shutdown_state {
350 const char *ip;
351 struct messaging_context *msg_ctx;
354 static int shutdown_other_smbds(const struct connections_key *key,
355 const struct connections_data *crec,
356 void *private_data)
358 struct shutdown_state *state = (struct shutdown_state *)private_data;
360 DEBUG(10, ("shutdown_other_smbds: %s, %s\n",
361 server_id_str(talloc_tos(), &crec->pid), crec->addr));
363 if (!process_exists(crec->pid)) {
364 DEBUG(10, ("process does not exist\n"));
365 return 0;
368 if (procid_is_me(&crec->pid)) {
369 DEBUG(10, ("It's me\n"));
370 return 0;
373 if (strcmp(state->ip, crec->addr) != 0) {
374 DEBUG(10, ("%s does not match %s\n", state->ip, crec->addr));
375 return 0;
378 DEBUG(1, ("shutdown_other_smbds: shutting down pid %u "
379 "(IP %s)\n", (unsigned int)procid_to_pid(&crec->pid),
380 state->ip));
382 messaging_send(state->msg_ctx, crec->pid, MSG_SHUTDOWN,
383 &data_blob_null);
384 return 0;
387 static void setup_new_vc_session(struct smbd_server_connection *sconn)
389 DEBUG(2,("setup_new_vc_session: New VC == 0, if NT4.x "
390 "compatible we would close all old resources.\n"));
391 #if 0
392 conn_close_all();
393 invalidate_all_vuids();
394 #endif
395 if (lp_reset_on_zero_vc()) {
396 char *addr;
397 struct shutdown_state state;
399 addr = tsocket_address_inet_addr_string(
400 sconn->remote_address, talloc_tos());
401 if (addr == NULL) {
402 return;
404 state.ip = addr;
405 state.msg_ctx = sconn->msg_ctx;
406 connections_forall_read(shutdown_other_smbds, &state);
407 TALLOC_FREE(addr);
411 /****************************************************************************
412 Reply to a session setup command.
413 ****************************************************************************/
415 void reply_sesssetup_and_X(struct smb_request *req)
417 int sess_vuid;
418 int smb_bufsize;
419 DATA_BLOB lm_resp;
420 DATA_BLOB nt_resp;
421 DATA_BLOB plaintext_password;
422 char *tmp;
423 const char *user;
424 fstring sub_user; /* Sanitised username for substituion */
425 const char *domain;
426 const char *native_os;
427 const char *native_lanman;
428 const char *primary_domain;
429 struct auth_usersupplied_info *user_info = NULL;
430 struct auth_serversupplied_info *server_info = NULL;
431 struct auth_session_info *session_info = NULL;
432 uint16 smb_flag2 = req->flags2;
434 NTSTATUS nt_status;
435 struct smbd_server_connection *sconn = req->sconn;
437 bool doencrypt = sconn->smb1.negprot.encrypted_passwords;
438 bool signing_allowed = false;
439 bool signing_mandatory = false;
441 START_PROFILE(SMBsesssetupX);
443 ZERO_STRUCT(lm_resp);
444 ZERO_STRUCT(nt_resp);
445 ZERO_STRUCT(plaintext_password);
447 DEBUG(3,("wct=%d flg2=0x%x\n", req->wct, req->flags2));
449 if (req->flags2 & FLAGS2_SMB_SECURITY_SIGNATURES) {
450 signing_allowed = true;
452 if (req->flags2 & FLAGS2_SMB_SECURITY_SIGNATURES_REQUIRED) {
453 signing_mandatory = true;
457 * We can call srv_set_signing_negotiated() each time.
458 * It finds out when it needs to turn into a noop
459 * itself.
461 srv_set_signing_negotiated(req->sconn,
462 signing_allowed,
463 signing_mandatory);
465 /* a SPNEGO session setup has 12 command words, whereas a normal
466 NT1 session setup has 13. See the cifs spec. */
467 if (req->wct == 12 &&
468 (req->flags2 & FLAGS2_EXTENDED_SECURITY)) {
470 if (!sconn->smb1.negprot.spnego) {
471 DEBUG(0,("reply_sesssetup_and_X: Rejecting attempt "
472 "at SPNEGO session setup when it was not "
473 "negotiated.\n"));
474 reply_nterror(req, nt_status_squash(
475 NT_STATUS_LOGON_FAILURE));
476 END_PROFILE(SMBsesssetupX);
477 return;
480 if (SVAL(req->vwv+4, 0) == 0) {
481 setup_new_vc_session(req->sconn);
484 reply_sesssetup_and_X_spnego(req);
485 END_PROFILE(SMBsesssetupX);
486 return;
489 smb_bufsize = SVAL(req->vwv+2, 0);
491 if (get_Protocol() < PROTOCOL_NT1) {
492 uint16 passlen1 = SVAL(req->vwv+7, 0);
494 /* Never do NT status codes with protocols before NT1 as we
495 * don't get client caps. */
496 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
498 if ((passlen1 > MAX_PASS_LEN) || (passlen1 > req->buflen)) {
499 reply_nterror(req, nt_status_squash(
500 NT_STATUS_INVALID_PARAMETER));
501 END_PROFILE(SMBsesssetupX);
502 return;
505 if (doencrypt) {
506 lm_resp = data_blob(req->buf, passlen1);
507 } else {
508 plaintext_password = data_blob(req->buf, passlen1+1);
509 /* Ensure null termination */
510 plaintext_password.data[passlen1] = 0;
513 srvstr_pull_req_talloc(talloc_tos(), req, &tmp,
514 req->buf + passlen1, STR_TERMINATE);
515 user = tmp ? tmp : "";
517 domain = "";
519 } else {
520 uint16 passlen1 = SVAL(req->vwv+7, 0);
521 uint16 passlen2 = SVAL(req->vwv+8, 0);
522 enum remote_arch_types ra_type = get_remote_arch();
523 const uint8_t *p = req->buf;
524 const uint8_t *save_p = req->buf;
525 uint16 byte_count;
528 if(global_client_caps == 0) {
529 global_client_caps = IVAL(req->vwv+11, 0);
531 if (!(global_client_caps & CAP_STATUS32)) {
532 remove_from_common_flags2(
533 FLAGS2_32_BIT_ERROR_CODES);
536 /* client_caps is used as final determination if
537 * client is NT or Win95. This is needed to return
538 * the correct error codes in some circumstances.
541 if(ra_type == RA_WINNT || ra_type == RA_WIN2K ||
542 ra_type == RA_WIN95) {
543 if(!(global_client_caps & (CAP_NT_SMBS|
544 CAP_STATUS32))) {
545 set_remote_arch( RA_WIN95);
550 if (!doencrypt) {
551 /* both Win95 and WinNT stuff up the password
552 * lengths for non-encrypting systems. Uggh.
554 if passlen1==24 its a win95 system, and its setting
555 the password length incorrectly. Luckily it still
556 works with the default code because Win95 will null
557 terminate the password anyway
559 if passlen1>0 and passlen2>0 then maybe its a NT box
560 and its setting passlen2 to some random value which
561 really stuffs things up. we need to fix that one. */
563 if (passlen1 > 0 && passlen2 > 0 && passlen2 != 24 &&
564 passlen2 != 1) {
565 passlen2 = 0;
569 /* check for nasty tricks */
570 if (passlen1 > MAX_PASS_LEN
571 || passlen1 > smbreq_bufrem(req, p)) {
572 reply_nterror(req, nt_status_squash(
573 NT_STATUS_INVALID_PARAMETER));
574 END_PROFILE(SMBsesssetupX);
575 return;
578 if (passlen2 > MAX_PASS_LEN
579 || passlen2 > smbreq_bufrem(req, p+passlen1)) {
580 reply_nterror(req, nt_status_squash(
581 NT_STATUS_INVALID_PARAMETER));
582 END_PROFILE(SMBsesssetupX);
583 return;
586 /* Save the lanman2 password and the NT md4 password. */
588 if ((doencrypt) && (passlen1 != 0) && (passlen1 != 24)) {
589 doencrypt = False;
592 if (doencrypt) {
593 lm_resp = data_blob(p, passlen1);
594 nt_resp = data_blob(p+passlen1, passlen2);
595 } else if (lp_security() != SEC_SHARE) {
597 * In share level we should ignore any passwords, so
598 * only read them if we're not.
600 char *pass = NULL;
601 bool unic= smb_flag2 & FLAGS2_UNICODE_STRINGS;
603 if (unic && (passlen2 == 0) && passlen1) {
604 /* Only a ascii plaintext password was sent. */
605 (void)srvstr_pull_talloc(talloc_tos(),
606 req->inbuf,
607 req->flags2,
608 &pass,
609 req->buf,
610 passlen1,
611 STR_TERMINATE|STR_ASCII);
612 } else {
613 (void)srvstr_pull_talloc(talloc_tos(),
614 req->inbuf,
615 req->flags2,
616 &pass,
617 req->buf,
618 unic ? passlen2 : passlen1,
619 STR_TERMINATE);
621 if (!pass) {
622 reply_nterror(req, nt_status_squash(
623 NT_STATUS_INVALID_PARAMETER));
624 END_PROFILE(SMBsesssetupX);
625 return;
627 plaintext_password = data_blob(pass, strlen(pass)+1);
630 p += passlen1 + passlen2;
632 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
633 STR_TERMINATE);
634 user = tmp ? tmp : "";
636 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
637 STR_TERMINATE);
638 domain = tmp ? tmp : "";
640 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
641 STR_TERMINATE);
642 native_os = tmp ? tmp : "";
644 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
645 STR_TERMINATE);
646 native_lanman = tmp ? tmp : "";
648 /* not documented or decoded by Ethereal but there is one more
649 * string in the extra bytes which is the same as the
650 * PrimaryDomain when using extended security. Windows NT 4
651 * and 2003 use this string to store the native lanman string.
652 * Windows 9x does not include a string here at all so we have
653 * to check if we have any extra bytes left */
655 byte_count = SVAL(req->vwv+13, 0);
656 if ( PTR_DIFF(p, save_p) < byte_count) {
657 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
658 STR_TERMINATE);
659 primary_domain = tmp ? tmp : "";
660 } else {
661 primary_domain = talloc_strdup(talloc_tos(), "null");
664 DEBUG(3,("Domain=[%s] NativeOS=[%s] NativeLanMan=[%s] "
665 "PrimaryDomain=[%s]\n",
666 domain, native_os, native_lanman, primary_domain));
668 if ( ra_type == RA_WIN2K ) {
669 if ( strlen(native_lanman) == 0 )
670 ra_lanman_string( primary_domain );
671 else
672 ra_lanman_string( native_lanman );
677 if (SVAL(req->vwv+4, 0) == 0) {
678 setup_new_vc_session(req->sconn);
681 DEBUG(3,("sesssetupX:name=[%s]\\[%s]@[%s]\n",
682 domain, user, get_remote_machine_name()));
684 if (*user) {
685 if (sconn->smb1.negprot.spnego) {
687 /* This has to be here, because this is a perfectly
688 * valid behaviour for guest logons :-( */
690 DEBUG(0,("reply_sesssetup_and_X: Rejecting attempt "
691 "at 'normal' session setup after "
692 "negotiating spnego.\n"));
693 reply_nterror(req, nt_status_squash(
694 NT_STATUS_LOGON_FAILURE));
695 END_PROFILE(SMBsesssetupX);
696 return;
698 fstrcpy(sub_user, user);
699 } else {
700 fstrcpy(sub_user, "");
703 sub_set_smb_name(sub_user);
705 reload_services(sconn, conn_snum_used, true);
707 if (lp_security() == SEC_SHARE) {
708 char *sub_user_mapped = NULL;
709 /* In share level we should ignore any passwords */
711 data_blob_free(&lm_resp);
712 data_blob_free(&nt_resp);
713 data_blob_clear_free(&plaintext_password);
715 (void)map_username(talloc_tos(), sub_user, &sub_user_mapped);
716 if (!sub_user_mapped) {
717 reply_nterror(req, NT_STATUS_NO_MEMORY);
718 END_PROFILE(SMBsesssetupX);
719 return;
721 fstrcpy(sub_user, sub_user_mapped);
722 add_session_user(sconn, sub_user);
723 add_session_workgroup(sconn, domain);
724 /* Then force it to null for the benfit of the code below */
725 user = "";
728 if (!*user) {
730 nt_status = check_guest_password(sconn->remote_address, &server_info);
732 } else if (doencrypt) {
733 struct auth_context *negprot_auth_context = NULL;
734 negprot_auth_context = sconn->smb1.negprot.auth_context;
735 if (!negprot_auth_context) {
736 DEBUG(0, ("reply_sesssetup_and_X: Attempted encrypted "
737 "session setup without negprot denied!\n"));
738 reply_nterror(req, nt_status_squash(
739 NT_STATUS_LOGON_FAILURE));
740 END_PROFILE(SMBsesssetupX);
741 return;
743 nt_status = make_user_info_for_reply_enc(&user_info, user,
744 domain,
745 sconn->remote_address,
746 lm_resp, nt_resp);
747 if (NT_STATUS_IS_OK(nt_status)) {
748 nt_status = negprot_auth_context->check_ntlm_password(
749 negprot_auth_context,
750 user_info,
751 &server_info);
753 } else {
754 struct auth_context *plaintext_auth_context = NULL;
756 nt_status = make_auth_context_subsystem(
757 talloc_tos(), &plaintext_auth_context);
759 if (NT_STATUS_IS_OK(nt_status)) {
760 uint8_t chal[8];
762 plaintext_auth_context->get_ntlm_challenge(
763 plaintext_auth_context, chal);
765 if (!make_user_info_for_reply(&user_info,
766 user, domain,
767 sconn->remote_address,
768 chal,
769 plaintext_password)) {
770 nt_status = NT_STATUS_NO_MEMORY;
773 if (NT_STATUS_IS_OK(nt_status)) {
774 nt_status = plaintext_auth_context->check_ntlm_password(
775 plaintext_auth_context,
776 user_info,
777 &server_info);
779 TALLOC_FREE(plaintext_auth_context);
784 free_user_info(&user_info);
786 if (!NT_STATUS_IS_OK(nt_status)) {
787 nt_status = do_map_to_guest_server_info(nt_status, &server_info,
788 user, domain);
791 if (!NT_STATUS_IS_OK(nt_status)) {
792 data_blob_free(&nt_resp);
793 data_blob_free(&lm_resp);
794 data_blob_clear_free(&plaintext_password);
795 reply_nterror(req, nt_status_squash(nt_status));
796 END_PROFILE(SMBsesssetupX);
797 return;
800 nt_status = create_local_token(req, server_info, NULL, sub_user, &session_info);
801 TALLOC_FREE(server_info);
803 if (!NT_STATUS_IS_OK(nt_status)) {
804 DEBUG(10, ("create_local_token failed: %s\n",
805 nt_errstr(nt_status)));
806 data_blob_free(&nt_resp);
807 data_blob_free(&lm_resp);
808 data_blob_clear_free(&plaintext_password);
809 reply_nterror(req, nt_status_squash(nt_status));
810 END_PROFILE(SMBsesssetupX);
811 return;
814 data_blob_clear_free(&plaintext_password);
816 /* it's ok - setup a reply */
817 reply_outbuf(req, 3, 0);
818 if (get_Protocol() >= PROTOCOL_NT1) {
819 push_signature(&req->outbuf);
820 /* perhaps grab OS version here?? */
823 if (security_session_user_level(session_info, NULL) < SECURITY_USER) {
824 SSVAL(req->outbuf,smb_vwv2,1);
827 /* register the name and uid as being validated, so further connections
828 to a uid can get through without a password, on the same VC */
830 if (lp_security() == SEC_SHARE) {
831 sess_vuid = UID_FIELD_INVALID;
832 TALLOC_FREE(session_info);
833 } else {
834 /* Ignore the initial vuid. */
835 sess_vuid = register_initial_vuid(sconn);
836 if (sess_vuid == UID_FIELD_INVALID) {
837 data_blob_free(&nt_resp);
838 data_blob_free(&lm_resp);
839 reply_nterror(req, nt_status_squash(
840 NT_STATUS_LOGON_FAILURE));
841 END_PROFILE(SMBsesssetupX);
842 return;
844 /* register_existing_vuid keeps the session_info */
845 sess_vuid = register_existing_vuid(sconn, sess_vuid,
846 session_info,
847 nt_resp.data ? nt_resp : lm_resp);
848 if (sess_vuid == UID_FIELD_INVALID) {
849 data_blob_free(&nt_resp);
850 data_blob_free(&lm_resp);
851 reply_nterror(req, nt_status_squash(
852 NT_STATUS_LOGON_FAILURE));
853 END_PROFILE(SMBsesssetupX);
854 return;
857 /* current_user_info is changed on new vuid */
858 reload_services(sconn, conn_snum_used, true);
861 data_blob_free(&nt_resp);
862 data_blob_free(&lm_resp);
864 SSVAL(req->outbuf,smb_uid,sess_vuid);
865 SSVAL(discard_const_p(char, req->inbuf),smb_uid,sess_vuid);
866 req->vuid = sess_vuid;
868 if (!sconn->smb1.sessions.done_sesssetup) {
869 sconn->smb1.sessions.max_send =
870 MIN(sconn->smb1.sessions.max_send,smb_bufsize);
872 sconn->smb1.sessions.done_sesssetup = true;
874 END_PROFILE(SMBsesssetupX);
875 chain_reply(req);
876 return;