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;
406 struct smbd_server_connection *sconn = req->sconn;
408 bool doencrypt = sconn->smb1.negprot.encrypted_passwords;
409 bool signing_allowed = false;
410 bool signing_mandatory = false;
412 START_PROFILE(SMBsesssetupX);
414 ZERO_STRUCT(lm_resp);
415 ZERO_STRUCT(nt_resp);
416 ZERO_STRUCT(plaintext_password);
418 DEBUG(3,("wct=%d flg2=0x%x\n", req->wct, req->flags2));
420 if (req->flags2 & FLAGS2_SMB_SECURITY_SIGNATURES) {
421 signing_allowed = true;
423 if (req->flags2 & FLAGS2_SMB_SECURITY_SIGNATURES_REQUIRED) {
424 signing_mandatory = true;
428 * We can call srv_set_signing_negotiated() each time.
429 * It finds out when it needs to turn into a noop
432 srv_set_signing_negotiated(req->sconn,
436 /* a SPNEGO session setup has 12 command words, whereas a normal
437 NT1 session setup has 13. See the cifs spec. */
438 if (req->wct == 12 &&
439 (req->flags2 & FLAGS2_EXTENDED_SECURITY)) {
441 if (!sconn->smb1.negprot.spnego) {
442 DEBUG(0,("reply_sesssetup_and_X: Rejecting attempt "
443 "at SPNEGO session setup when it was not "
445 reply_nterror(req, nt_status_squash(
446 NT_STATUS_LOGON_FAILURE));
447 END_PROFILE(SMBsesssetupX);
451 if (SVAL(req->vwv+4, 0) == 0) {
452 setup_new_vc_session(req->sconn);
455 reply_sesssetup_and_X_spnego(req);
456 END_PROFILE(SMBsesssetupX);
460 smb_bufsize = SVAL(req->vwv+2, 0);
462 if (get_Protocol() < PROTOCOL_NT1) {
463 uint16 passlen1 = SVAL(req->vwv+7, 0);
465 /* Never do NT status codes with protocols before NT1 as we
466 * don't get client caps. */
467 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
469 if ((passlen1 > MAX_PASS_LEN) || (passlen1 > req->buflen)) {
470 reply_nterror(req, nt_status_squash(
471 NT_STATUS_INVALID_PARAMETER));
472 END_PROFILE(SMBsesssetupX);
477 lm_resp = data_blob(req->buf, passlen1);
479 plaintext_password = data_blob(req->buf, passlen1+1);
480 /* Ensure null termination */
481 plaintext_password.data[passlen1] = 0;
484 srvstr_pull_req_talloc(talloc_tos(), req, &tmp,
485 req->buf + passlen1, STR_TERMINATE);
486 user = tmp ? tmp : "";
491 uint16 passlen1 = SVAL(req->vwv+7, 0);
492 uint16 passlen2 = SVAL(req->vwv+8, 0);
493 enum remote_arch_types ra_type = get_remote_arch();
494 const uint8_t *p = req->buf;
495 const uint8_t *save_p = req->buf;
499 if(global_client_caps == 0) {
500 global_client_caps = IVAL(req->vwv+11, 0);
502 if (!(global_client_caps & CAP_STATUS32)) {
503 remove_from_common_flags2(
504 FLAGS2_32_BIT_ERROR_CODES);
507 /* client_caps is used as final determination if
508 * client is NT or Win95. This is needed to return
509 * the correct error codes in some circumstances.
512 if(ra_type == RA_WINNT || ra_type == RA_WIN2K ||
513 ra_type == RA_WIN95) {
514 if(!(global_client_caps & (CAP_NT_SMBS|
516 set_remote_arch( RA_WIN95);
522 /* both Win95 and WinNT stuff up the password
523 * lengths for non-encrypting systems. Uggh.
525 if passlen1==24 its a win95 system, and its setting
526 the password length incorrectly. Luckily it still
527 works with the default code because Win95 will null
528 terminate the password anyway
530 if passlen1>0 and passlen2>0 then maybe its a NT box
531 and its setting passlen2 to some random value which
532 really stuffs things up. we need to fix that one. */
534 if (passlen1 > 0 && passlen2 > 0 && passlen2 != 24 &&
540 /* check for nasty tricks */
541 if (passlen1 > MAX_PASS_LEN
542 || passlen1 > smbreq_bufrem(req, p)) {
543 reply_nterror(req, nt_status_squash(
544 NT_STATUS_INVALID_PARAMETER));
545 END_PROFILE(SMBsesssetupX);
549 if (passlen2 > MAX_PASS_LEN
550 || passlen2 > smbreq_bufrem(req, p+passlen1)) {
551 reply_nterror(req, nt_status_squash(
552 NT_STATUS_INVALID_PARAMETER));
553 END_PROFILE(SMBsesssetupX);
557 /* Save the lanman2 password and the NT md4 password. */
559 if ((doencrypt) && (passlen1 != 0) && (passlen1 != 24)) {
564 lm_resp = data_blob(p, passlen1);
565 nt_resp = data_blob(p+passlen1, passlen2);
568 bool unic= smb_flag2 & FLAGS2_UNICODE_STRINGS;
570 if (unic && (passlen2 == 0) && passlen1) {
571 /* Only a ascii plaintext password was sent. */
572 (void)srvstr_pull_talloc(talloc_tos(),
578 STR_TERMINATE|STR_ASCII);
580 (void)srvstr_pull_talloc(talloc_tos(),
585 unic ? passlen2 : passlen1,
589 reply_nterror(req, nt_status_squash(
590 NT_STATUS_INVALID_PARAMETER));
591 END_PROFILE(SMBsesssetupX);
594 plaintext_password = data_blob(pass, strlen(pass)+1);
597 p += passlen1 + passlen2;
599 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
601 user = tmp ? tmp : "";
603 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
605 domain = tmp ? tmp : "";
607 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
609 native_os = tmp ? tmp : "";
611 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
613 native_lanman = tmp ? tmp : "";
615 /* not documented or decoded by Ethereal but there is one more
616 * string in the extra bytes which is the same as the
617 * PrimaryDomain when using extended security. Windows NT 4
618 * and 2003 use this string to store the native lanman string.
619 * Windows 9x does not include a string here at all so we have
620 * to check if we have any extra bytes left */
622 byte_count = SVAL(req->vwv+13, 0);
623 if ( PTR_DIFF(p, save_p) < byte_count) {
624 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
626 primary_domain = tmp ? tmp : "";
628 primary_domain = talloc_strdup(talloc_tos(), "null");
631 DEBUG(3,("Domain=[%s] NativeOS=[%s] NativeLanMan=[%s] "
632 "PrimaryDomain=[%s]\n",
633 domain, native_os, native_lanman, primary_domain));
635 if ( ra_type == RA_WIN2K ) {
636 if ( strlen(native_lanman) == 0 )
637 ra_lanman_string( primary_domain );
639 ra_lanman_string( native_lanman );
644 if (SVAL(req->vwv+4, 0) == 0) {
645 setup_new_vc_session(req->sconn);
648 DEBUG(3,("sesssetupX:name=[%s]\\[%s]@[%s]\n",
649 domain, user, get_remote_machine_name()));
652 if (sconn->smb1.negprot.spnego) {
654 /* This has to be here, because this is a perfectly
655 * valid behaviour for guest logons :-( */
657 DEBUG(0,("reply_sesssetup_and_X: Rejecting attempt "
658 "at 'normal' session setup after "
659 "negotiating spnego.\n"));
660 reply_nterror(req, nt_status_squash(
661 NT_STATUS_LOGON_FAILURE));
662 END_PROFILE(SMBsesssetupX);
665 fstrcpy(sub_user, user);
667 fstrcpy(sub_user, "");
670 sub_set_smb_name(sub_user);
672 reload_services(sconn, conn_snum_used, true);
676 nt_status = check_guest_password(sconn->remote_address, req, &session_info);
678 } else if (doencrypt) {
679 struct auth4_context *negprot_auth_context = NULL;
680 negprot_auth_context = sconn->smb1.negprot.auth_context;
681 if (!negprot_auth_context) {
682 DEBUG(0, ("reply_sesssetup_and_X: Attempted encrypted "
683 "session setup without negprot denied!\n"));
684 reply_nterror(req, nt_status_squash(
685 NT_STATUS_LOGON_FAILURE));
686 END_PROFILE(SMBsesssetupX);
689 nt_status = make_user_info_for_reply_enc(&user_info, user,
691 sconn->remote_address,
693 if (NT_STATUS_IS_OK(nt_status)) {
694 nt_status = auth_check_password_session_info(negprot_auth_context,
695 req, user_info, &session_info);
698 struct auth4_context *plaintext_auth_context = NULL;
700 nt_status = make_auth4_context(
701 talloc_tos(), &plaintext_auth_context);
703 if (NT_STATUS_IS_OK(nt_status)) {
706 plaintext_auth_context->get_ntlm_challenge(
707 plaintext_auth_context, chal);
709 if (!make_user_info_for_reply(&user_info,
711 sconn->remote_address,
713 plaintext_password)) {
714 nt_status = NT_STATUS_NO_MEMORY;
717 if (NT_STATUS_IS_OK(nt_status)) {
718 nt_status = auth_check_password_session_info(plaintext_auth_context,
719 req, user_info, &session_info);
721 TALLOC_FREE(plaintext_auth_context);
725 free_user_info(&user_info);
727 if (!NT_STATUS_IS_OK(nt_status)) {
728 data_blob_free(&nt_resp);
729 data_blob_free(&lm_resp);
730 data_blob_clear_free(&plaintext_password);
731 reply_nterror(req, nt_status_squash(nt_status));
732 END_PROFILE(SMBsesssetupX);
736 data_blob_clear_free(&plaintext_password);
738 /* it's ok - setup a reply */
739 reply_outbuf(req, 3, 0);
740 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
741 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
743 if (get_Protocol() >= PROTOCOL_NT1) {
744 push_signature(&req->outbuf);
745 /* perhaps grab OS version here?? */
748 if (security_session_user_level(session_info, NULL) < SECURITY_USER) {
752 /* register the name and uid as being validated, so further connections
753 to a uid can get through without a password, on the same VC */
755 /* Ignore the initial vuid. */
756 sess_vuid = register_initial_vuid(sconn);
757 if (sess_vuid == UID_FIELD_INVALID) {
758 data_blob_free(&nt_resp);
759 data_blob_free(&lm_resp);
760 reply_nterror(req, nt_status_squash(
761 NT_STATUS_LOGON_FAILURE));
762 END_PROFILE(SMBsesssetupX);
765 /* register_existing_vuid keeps the session_info */
766 sess_vuid = register_existing_vuid(sconn, sess_vuid,
768 nt_resp.data ? nt_resp : lm_resp);
769 if (sess_vuid == UID_FIELD_INVALID) {
770 data_blob_free(&nt_resp);
771 data_blob_free(&lm_resp);
772 reply_nterror(req, nt_status_squash(
773 NT_STATUS_LOGON_FAILURE));
774 END_PROFILE(SMBsesssetupX);
778 /* current_user_info is changed on new vuid */
779 reload_services(sconn, conn_snum_used, true);
781 data_blob_free(&nt_resp);
782 data_blob_free(&lm_resp);
784 SSVAL(req->outbuf,smb_vwv2,action);
785 SSVAL(req->outbuf,smb_uid,sess_vuid);
786 SSVAL(discard_const_p(char, req->inbuf),smb_uid,sess_vuid);
787 req->vuid = sess_vuid;
789 if (!sconn->smb1.sessions.done_sesssetup) {
790 sconn->smb1.sessions.max_send =
791 MIN(sconn->smb1.sessions.max_send,smb_bufsize);
793 sconn->smb1.sessions.done_sesssetup = true;
795 END_PROFILE(SMBsesssetupX);