2 Unix SMB/CIFS implementation.
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/>.
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"
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)
51 tmp = message_push_string(outbuf, "Unix", STR_TERMINATE);
53 if (tmp == -1) return -1;
56 if (asprintf(&lanman, "Samba %s", samba_version_string()) != -1) {
57 tmp = message_push_string(outbuf, lanman, STR_TERMINATE);
61 tmp = message_push_string(outbuf, "Samba", STR_TERMINATE);
64 if (tmp == -1) return -1;
67 tmp = message_push_string(outbuf, lp_workgroup(), STR_TERMINATE);
69 if (tmp == -1) return -1;
75 /****************************************************************************
76 Do a 'guest' logon, getting back the
77 ****************************************************************************/
79 static NTSTATUS check_guest_password(const struct tsocket_address *remote_address,
81 struct auth_session_info **session_info)
83 struct auth4_context *auth_context;
84 struct auth_usersupplied_info *user_info = NULL;
88 DEBUG(3,("Got anonymous request\n"));
90 nt_status = make_auth4_context(talloc_tos(), &auth_context);
91 if (!NT_STATUS_IS_OK(nt_status)) {
95 auth_context->get_ntlm_challenge(auth_context,
98 if (!make_user_info_guest(remote_address, &user_info)) {
99 TALLOC_FREE(auth_context);
100 return NT_STATUS_NO_MEMORY;
103 nt_status = auth_check_password_session_info(auth_context,
104 mem_ctx, user_info, session_info);
105 free_user_info(&user_info);
106 TALLOC_FREE(auth_context);
110 /****************************************************************************
111 Reply to a session setup command.
112 conn POINTER CAN BE NULL HERE !
113 ****************************************************************************/
115 static void reply_sesssetup_and_X_spnego(struct smb_request *req)
119 DATA_BLOB out_blob = data_blob_null;
122 const char *native_os;
123 const char *native_lanman;
124 const char *primary_domain;
126 uint16 data_blob_len = SVAL(req->vwv+7, 0);
127 enum remote_arch_types ra_type = get_remote_arch();
128 int vuid = req->vuid;
129 user_struct *vuser = NULL;
130 NTSTATUS status = NT_STATUS_OK;
131 struct smbd_server_connection *sconn = req->sconn;
134 DEBUG(3,("Doing spnego session setup\n"));
136 if (global_client_caps == 0) {
137 global_client_caps = IVAL(req->vwv+10, 0);
139 if (!(global_client_caps & CAP_STATUS32)) {
140 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
146 if (data_blob_len == 0) {
147 /* an invalid request */
148 reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
152 bufrem = smbreq_bufrem(req, p);
153 /* pull the spnego blob */
154 in_blob = data_blob_const(p, MIN(bufrem, data_blob_len));
157 file_save("negotiate.dat", in_blob.data, in_blob.length);
160 p2 = (const char *)req->buf + in_blob.length;
162 p2 += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p2,
164 native_os = tmp ? tmp : "";
166 p2 += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p2,
168 native_lanman = tmp ? tmp : "";
170 p2 += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p2,
172 primary_domain = tmp ? tmp : "";
174 DEBUG(3,("NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n",
175 native_os, native_lanman, primary_domain));
177 if ( ra_type == RA_WIN2K ) {
178 /* Vista sets neither the OS or lanman strings */
180 if ( !strlen(native_os) && !strlen(native_lanman) )
181 set_remote_arch(RA_VISTA);
183 /* Windows 2003 doesn't set the native lanman string,
184 but does set primary domain which is a bug I think */
186 if ( !strlen(native_lanman) ) {
187 ra_lanman_string( primary_domain );
189 ra_lanman_string( native_lanman );
191 } else if ( ra_type == RA_VISTA ) {
192 if ( strncmp(native_os, "Mac OS X", 8) == 0 ) {
193 set_remote_arch(RA_OSX);
197 vuser = get_valid_user_struct(sconn, vuid);
199 reply_nterror(req, NT_STATUS_REQUEST_NOT_ACCEPTED);
203 /* Do we have a valid vuid now ? */
204 if (!is_partial_auth_vuid(sconn, vuid)) {
205 /* No, start a new authentication setup. */
206 vuid = register_initial_vuid(sconn);
207 if (vuid == UID_FIELD_INVALID) {
208 reply_nterror(req, nt_status_squash(
209 NT_STATUS_INVALID_PARAMETER));
214 vuser = get_partial_auth_user_struct(sconn, vuid);
215 /* This MUST be valid. */
217 smb_panic("reply_sesssetup_and_X_spnego: invalid vuid.");
220 if (!vuser->gensec_security) {
221 status = auth_generic_prepare(vuser, sconn->remote_address,
222 &vuser->gensec_security);
223 if (!NT_STATUS_IS_OK(status)) {
224 /* Kill the intermediate vuid */
225 invalidate_vuid(sconn, vuid);
226 reply_nterror(req, nt_status_squash(status));
230 gensec_want_feature(vuser->gensec_security, GENSEC_FEATURE_SESSION_KEY);
231 gensec_want_feature(vuser->gensec_security, GENSEC_FEATURE_UNIX_TOKEN);
233 status = gensec_start_mech_by_oid(vuser->gensec_security, GENSEC_OID_SPNEGO);
234 if (!NT_STATUS_IS_OK(status)) {
235 DEBUG(0, ("Failed to start SPNEGO handler!\n"));
236 /* Kill the intermediate vuid */
237 invalidate_vuid(sconn, vuid);
238 reply_nterror(req, nt_status_squash(status));
243 status = gensec_update(vuser->gensec_security,
246 if (!NT_STATUS_IS_OK(status) &&
247 !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
248 /* Kill the intermediate vuid */
249 invalidate_vuid(sconn, vuid);
250 reply_nterror(req, nt_status_squash(status));
254 if (NT_STATUS_IS_OK(status)) {
255 struct auth_session_info *session_info = NULL;
258 status = gensec_session_info(vuser->gensec_security,
261 if (!NT_STATUS_IS_OK(status)) {
262 DEBUG(1,("Failed to generate session_info "
263 "(user and group token) for session setup: %s\n",
265 /* Kill the intermediate vuid */
266 data_blob_free(&out_blob);
267 invalidate_vuid(sconn, vuid);
268 reply_nterror(req, nt_status_squash(status));
272 if (security_session_user_level(session_info, NULL) < SECURITY_USER) {
276 /* register_existing_vuid keeps the server info */
277 tmp_vuid = register_existing_vuid(sconn, vuid,
280 if (tmp_vuid != vuid) {
281 data_blob_free(&out_blob);
282 invalidate_vuid(sconn, vuid);
283 reply_nterror(req, NT_STATUS_LOGON_FAILURE);
287 /* current_user_info is changed on new vuid */
288 reload_services(sconn, conn_snum_used, true);
291 reply_outbuf(req, 4, 0);
293 SSVAL(req->outbuf, smb_uid, vuid);
294 SIVAL(req->outbuf, smb_rcls, NT_STATUS_V(status));
295 SSVAL(req->outbuf, smb_vwv0, 0xFF); /* no chaining possible */
296 SSVAL(req->outbuf, smb_vwv2, action);
297 SSVAL(req->outbuf, smb_vwv3, out_blob.length);
299 if (message_push_blob(&req->outbuf, out_blob) == -1) {
300 data_blob_free(&out_blob);
301 invalidate_vuid(sconn, vuid);
302 reply_nterror(req, NT_STATUS_NO_MEMORY);
305 data_blob_free(&out_blob);
307 if (push_signature(&req->outbuf) == -1) {
308 invalidate_vuid(sconn, vuid);
309 reply_nterror(req, NT_STATUS_NO_MEMORY);
314 /****************************************************************************
315 On new VC == 0, shutdown *all* old connections and users.
316 It seems that only NT4.x does this. At W2K and above (XP etc.).
317 a new session setup with VC==0 is ignored.
318 ****************************************************************************/
320 struct shutdown_state {
322 struct messaging_context *msg_ctx;
325 static int shutdown_other_smbds(const struct connections_key *key,
326 const struct connections_data *crec,
329 struct shutdown_state *state = (struct shutdown_state *)private_data;
331 DEBUG(10, ("shutdown_other_smbds: %s, %s\n",
332 server_id_str(talloc_tos(), &crec->pid), crec->addr));
334 if (!process_exists(crec->pid)) {
335 DEBUG(10, ("process does not exist\n"));
339 if (procid_is_me(&crec->pid)) {
340 DEBUG(10, ("It's me\n"));
344 if (strcmp(state->ip, crec->addr) != 0) {
345 DEBUG(10, ("%s does not match %s\n", state->ip, crec->addr));
349 DEBUG(1, ("shutdown_other_smbds: shutting down pid %u "
350 "(IP %s)\n", (unsigned int)procid_to_pid(&crec->pid),
353 messaging_send(state->msg_ctx, crec->pid, MSG_SHUTDOWN,
358 static void setup_new_vc_session(struct smbd_server_connection *sconn)
360 DEBUG(2,("setup_new_vc_session: New VC == 0, if NT4.x "
361 "compatible we would close all old resources.\n"));
364 invalidate_all_vuids();
366 if (lp_reset_on_zero_vc()) {
368 struct shutdown_state state;
370 addr = tsocket_address_inet_addr_string(
371 sconn->remote_address, talloc_tos());
376 state.msg_ctx = sconn->msg_ctx;
377 connections_forall_read(shutdown_other_smbds, &state);
382 /****************************************************************************
383 Reply to a session setup command.
384 ****************************************************************************/
386 void reply_sesssetup_and_X(struct smb_request *req)
392 DATA_BLOB plaintext_password;
395 fstring sub_user; /* Sanitised username for substituion */
397 const char *native_os;
398 const char *native_lanman;
399 const char *primary_domain;
400 struct auth_usersupplied_info *user_info = NULL;
401 struct auth_session_info *session_info = NULL;
402 uint16 smb_flag2 = req->flags2;
405 struct smbd_server_connection *sconn = req->sconn;
407 bool doencrypt = sconn->smb1.negprot.encrypted_passwords;
408 bool signing_allowed = false;
409 bool signing_mandatory = false;
411 START_PROFILE(SMBsesssetupX);
413 ZERO_STRUCT(lm_resp);
414 ZERO_STRUCT(nt_resp);
415 ZERO_STRUCT(plaintext_password);
417 DEBUG(3,("wct=%d flg2=0x%x\n", req->wct, req->flags2));
419 if (req->flags2 & FLAGS2_SMB_SECURITY_SIGNATURES) {
420 signing_allowed = true;
422 if (req->flags2 & FLAGS2_SMB_SECURITY_SIGNATURES_REQUIRED) {
423 signing_mandatory = true;
427 * We can call srv_set_signing_negotiated() each time.
428 * It finds out when it needs to turn into a noop
431 srv_set_signing_negotiated(req->sconn,
435 /* a SPNEGO session setup has 12 command words, whereas a normal
436 NT1 session setup has 13. See the cifs spec. */
437 if (req->wct == 12 &&
438 (req->flags2 & FLAGS2_EXTENDED_SECURITY)) {
440 if (!sconn->smb1.negprot.spnego) {
441 DEBUG(0,("reply_sesssetup_and_X: Rejecting attempt "
442 "at SPNEGO session setup when it was not "
444 reply_nterror(req, nt_status_squash(
445 NT_STATUS_LOGON_FAILURE));
446 END_PROFILE(SMBsesssetupX);
450 if (SVAL(req->vwv+4, 0) == 0) {
451 setup_new_vc_session(req->sconn);
454 reply_sesssetup_and_X_spnego(req);
455 END_PROFILE(SMBsesssetupX);
459 smb_bufsize = SVAL(req->vwv+2, 0);
461 if (get_Protocol() < PROTOCOL_NT1) {
462 uint16 passlen1 = SVAL(req->vwv+7, 0);
464 /* Never do NT status codes with protocols before NT1 as we
465 * don't get client caps. */
466 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
468 if ((passlen1 > MAX_PASS_LEN) || (passlen1 > req->buflen)) {
469 reply_nterror(req, nt_status_squash(
470 NT_STATUS_INVALID_PARAMETER));
471 END_PROFILE(SMBsesssetupX);
476 lm_resp = data_blob(req->buf, passlen1);
478 plaintext_password = data_blob(req->buf, passlen1+1);
479 /* Ensure null termination */
480 plaintext_password.data[passlen1] = 0;
483 srvstr_pull_req_talloc(talloc_tos(), req, &tmp,
484 req->buf + passlen1, STR_TERMINATE);
485 user = tmp ? tmp : "";
490 uint16 passlen1 = SVAL(req->vwv+7, 0);
491 uint16 passlen2 = SVAL(req->vwv+8, 0);
492 enum remote_arch_types ra_type = get_remote_arch();
493 const uint8_t *p = req->buf;
494 const uint8_t *save_p = req->buf;
498 if(global_client_caps == 0) {
499 global_client_caps = IVAL(req->vwv+11, 0);
501 if (!(global_client_caps & CAP_STATUS32)) {
502 remove_from_common_flags2(
503 FLAGS2_32_BIT_ERROR_CODES);
506 /* client_caps is used as final determination if
507 * client is NT or Win95. This is needed to return
508 * the correct error codes in some circumstances.
511 if(ra_type == RA_WINNT || ra_type == RA_WIN2K ||
512 ra_type == RA_WIN95) {
513 if(!(global_client_caps & (CAP_NT_SMBS|
515 set_remote_arch( RA_WIN95);
521 /* both Win95 and WinNT stuff up the password
522 * lengths for non-encrypting systems. Uggh.
524 if passlen1==24 its a win95 system, and its setting
525 the password length incorrectly. Luckily it still
526 works with the default code because Win95 will null
527 terminate the password anyway
529 if passlen1>0 and passlen2>0 then maybe its a NT box
530 and its setting passlen2 to some random value which
531 really stuffs things up. we need to fix that one. */
533 if (passlen1 > 0 && passlen2 > 0 && passlen2 != 24 &&
539 /* check for nasty tricks */
540 if (passlen1 > MAX_PASS_LEN
541 || passlen1 > smbreq_bufrem(req, p)) {
542 reply_nterror(req, nt_status_squash(
543 NT_STATUS_INVALID_PARAMETER));
544 END_PROFILE(SMBsesssetupX);
548 if (passlen2 > MAX_PASS_LEN
549 || passlen2 > smbreq_bufrem(req, p+passlen1)) {
550 reply_nterror(req, nt_status_squash(
551 NT_STATUS_INVALID_PARAMETER));
552 END_PROFILE(SMBsesssetupX);
556 /* Save the lanman2 password and the NT md4 password. */
558 if ((doencrypt) && (passlen1 != 0) && (passlen1 != 24)) {
563 lm_resp = data_blob(p, passlen1);
564 nt_resp = data_blob(p+passlen1, passlen2);
567 bool unic= smb_flag2 & FLAGS2_UNICODE_STRINGS;
569 if (unic && (passlen2 == 0) && passlen1) {
570 /* Only a ascii plaintext password was sent. */
571 (void)srvstr_pull_talloc(talloc_tos(),
577 STR_TERMINATE|STR_ASCII);
579 (void)srvstr_pull_talloc(talloc_tos(),
584 unic ? passlen2 : passlen1,
588 reply_nterror(req, nt_status_squash(
589 NT_STATUS_INVALID_PARAMETER));
590 END_PROFILE(SMBsesssetupX);
593 plaintext_password = data_blob(pass, strlen(pass)+1);
596 p += passlen1 + passlen2;
598 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
600 user = tmp ? tmp : "";
602 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
604 domain = tmp ? tmp : "";
606 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
608 native_os = tmp ? tmp : "";
610 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
612 native_lanman = tmp ? tmp : "";
614 /* not documented or decoded by Ethereal but there is one more
615 * string in the extra bytes which is the same as the
616 * PrimaryDomain when using extended security. Windows NT 4
617 * and 2003 use this string to store the native lanman string.
618 * Windows 9x does not include a string here at all so we have
619 * to check if we have any extra bytes left */
621 byte_count = SVAL(req->vwv+13, 0);
622 if ( PTR_DIFF(p, save_p) < byte_count) {
623 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
625 primary_domain = tmp ? tmp : "";
627 primary_domain = talloc_strdup(talloc_tos(), "null");
630 DEBUG(3,("Domain=[%s] NativeOS=[%s] NativeLanMan=[%s] "
631 "PrimaryDomain=[%s]\n",
632 domain, native_os, native_lanman, primary_domain));
634 if ( ra_type == RA_WIN2K ) {
635 if ( strlen(native_lanman) == 0 )
636 ra_lanman_string( primary_domain );
638 ra_lanman_string( native_lanman );
643 if (SVAL(req->vwv+4, 0) == 0) {
644 setup_new_vc_session(req->sconn);
647 DEBUG(3,("sesssetupX:name=[%s]\\[%s]@[%s]\n",
648 domain, user, get_remote_machine_name()));
651 if (sconn->smb1.negprot.spnego) {
653 /* This has to be here, because this is a perfectly
654 * valid behaviour for guest logons :-( */
656 DEBUG(0,("reply_sesssetup_and_X: Rejecting attempt "
657 "at 'normal' session setup after "
658 "negotiating spnego.\n"));
659 reply_nterror(req, nt_status_squash(
660 NT_STATUS_LOGON_FAILURE));
661 END_PROFILE(SMBsesssetupX);
664 fstrcpy(sub_user, user);
666 fstrcpy(sub_user, "");
669 sub_set_smb_name(sub_user);
671 reload_services(sconn, conn_snum_used, true);
675 nt_status = check_guest_password(sconn->remote_address, req, &session_info);
677 } else if (doencrypt) {
678 struct auth4_context *negprot_auth_context = NULL;
679 negprot_auth_context = sconn->smb1.negprot.auth_context;
680 if (!negprot_auth_context) {
681 DEBUG(0, ("reply_sesssetup_and_X: Attempted encrypted "
682 "session setup without negprot denied!\n"));
683 reply_nterror(req, nt_status_squash(
684 NT_STATUS_LOGON_FAILURE));
685 END_PROFILE(SMBsesssetupX);
688 nt_status = make_user_info_for_reply_enc(&user_info, user,
690 sconn->remote_address,
692 if (NT_STATUS_IS_OK(nt_status)) {
693 nt_status = auth_check_password_session_info(negprot_auth_context,
694 req, user_info, &session_info);
697 struct auth4_context *plaintext_auth_context = NULL;
699 nt_status = make_auth4_context(
700 talloc_tos(), &plaintext_auth_context);
702 if (NT_STATUS_IS_OK(nt_status)) {
705 plaintext_auth_context->get_ntlm_challenge(
706 plaintext_auth_context, chal);
708 if (!make_user_info_for_reply(&user_info,
710 sconn->remote_address,
712 plaintext_password)) {
713 nt_status = NT_STATUS_NO_MEMORY;
716 if (NT_STATUS_IS_OK(nt_status)) {
717 nt_status = auth_check_password_session_info(plaintext_auth_context,
718 req, user_info, &session_info);
720 TALLOC_FREE(plaintext_auth_context);
724 free_user_info(&user_info);
726 if (!NT_STATUS_IS_OK(nt_status)) {
727 data_blob_free(&nt_resp);
728 data_blob_free(&lm_resp);
729 data_blob_clear_free(&plaintext_password);
730 reply_nterror(req, nt_status_squash(nt_status));
731 END_PROFILE(SMBsesssetupX);
735 data_blob_clear_free(&plaintext_password);
737 /* it's ok - setup a reply */
738 reply_outbuf(req, 3, 0);
739 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
740 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
742 if (get_Protocol() >= PROTOCOL_NT1) {
743 push_signature(&req->outbuf);
744 /* perhaps grab OS version here?? */
747 if (security_session_user_level(session_info, NULL) < SECURITY_USER) {
748 SSVAL(req->outbuf,smb_vwv2,1);
751 /* register the name and uid as being validated, so further connections
752 to a uid can get through without a password, on the same VC */
754 /* Ignore the initial vuid. */
755 sess_vuid = register_initial_vuid(sconn);
756 if (sess_vuid == UID_FIELD_INVALID) {
757 data_blob_free(&nt_resp);
758 data_blob_free(&lm_resp);
759 reply_nterror(req, nt_status_squash(
760 NT_STATUS_LOGON_FAILURE));
761 END_PROFILE(SMBsesssetupX);
764 /* register_existing_vuid keeps the session_info */
765 sess_vuid = register_existing_vuid(sconn, sess_vuid,
767 nt_resp.data ? nt_resp : lm_resp);
768 if (sess_vuid == UID_FIELD_INVALID) {
769 data_blob_free(&nt_resp);
770 data_blob_free(&lm_resp);
771 reply_nterror(req, nt_status_squash(
772 NT_STATUS_LOGON_FAILURE));
773 END_PROFILE(SMBsesssetupX);
777 /* current_user_info is changed on new vuid */
778 reload_services(sconn, conn_snum_used, true);
780 data_blob_free(&nt_resp);
781 data_blob_free(&lm_resp);
783 SSVAL(req->outbuf,smb_uid,sess_vuid);
784 SSVAL(discard_const_p(char, req->inbuf),smb_uid,sess_vuid);
785 req->vuid = sess_vuid;
787 if (!sconn->smb1.sessions.done_sesssetup) {
788 sconn->smb1.sessions.max_send =
789 MIN(sconn->smb1.sessions.max_send,smb_bufsize);
791 sconn->smb1.sessions.done_sesssetup = true;
793 END_PROFILE(SMBsesssetupX);