2 Unix SMB/CIFS implementation.
4 Copyright (C) Andrew Tridgell 1998-2001
5 Copyright (C) Andrew Bartlett 2001
6 Copyright (C) Jim McDonough 2002
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 2 of the License, or
11 (at your option) any later version.
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.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 uint32 global_client_caps = 0;
27 static struct auth_ntlmssp_state *global_ntlmssp_state;
30 on a logon error possibly map the error to success if "map to guest"
33 static NTSTATUS do_map_to_guest(NTSTATUS status, auth_serversupplied_info **server_info,
34 const char *user, const char *domain)
36 if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
37 if ((lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_USER) ||
38 (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD)) {
39 DEBUG(3,("No such user %s [%s] - using guest account\n",
41 make_server_info_guest(server_info);
42 status = NT_STATUS_OK;
46 if (NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
47 if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD) {
48 DEBUG(3,("Registered username %s for guest access\n",user));
49 make_server_info_guest(server_info);
50 status = NT_STATUS_OK;
58 /****************************************************************************
59 Add the standard 'Samba' signature to the end of the session setup.
60 ****************************************************************************/
61 static void add_signature(char *outbuf)
65 p += srvstr_push(outbuf, p, "Unix", -1, STR_TERMINATE);
66 p += srvstr_push(outbuf, p, "Samba", -1, STR_TERMINATE);
67 p += srvstr_push(outbuf, p, lp_workgroup(), -1, STR_TERMINATE);
68 set_message_end(outbuf,p);
71 /****************************************************************************
72 Do a 'guest' logon, getting back the
73 ****************************************************************************/
74 static NTSTATUS check_guest_password(auth_serversupplied_info **server_info)
76 struct auth_context *auth_context;
77 auth_usersupplied_info *user_info = NULL;
80 unsigned char chal[8];
84 DEBUG(3,("Got anonymous request\n"));
86 if (!NT_STATUS_IS_OK(nt_status = make_auth_context_fixed(&auth_context, chal))) {
90 if (!make_user_info_guest(&user_info)) {
91 (auth_context->free)(&auth_context);
92 return NT_STATUS_NO_MEMORY;
95 nt_status = auth_context->check_ntlm_password(auth_context, user_info, server_info);
96 (auth_context->free)(&auth_context);
97 free_user_info(&user_info);
103 /****************************************************************************
104 reply to a session setup spnego negotiate packet for kerberos
105 ****************************************************************************/
106 static int reply_spnego_kerberos(connection_struct *conn,
107 char *inbuf, char *outbuf,
108 int length, int bufsize,
113 const struct passwd *pw;
118 auth_serversupplied_info *server_info = NULL;
121 if (!spnego_parse_krb5_wrap(*secblob, &ticket)) {
122 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
125 ads = ads_init_simple();
128 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
131 ads->auth.realm = strdup(lp_realm());
133 ret = ads_verify_ticket(ads, &ticket, &client, &auth_data);
134 if (!NT_STATUS_IS_OK(ret)) {
135 DEBUG(1,("Failed to verify incoming ticket!\n"));
137 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
140 DEBUG(3,("Ticket name is [%s]\n", client));
142 p = strchr_m(client, '@');
144 DEBUG(3,("Doesn't look like a valid principal\n"));
146 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
150 if (strcasecmp(p+1, ads->auth.realm) != 0) {
151 DEBUG(3,("Ticket for foreign realm %s@%s\n", client, p+1));
152 if (!lp_allow_trusted_domains()) {
153 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
155 /* this gives a fully qualified user name (ie. with full realm).
156 that leads to very long usernames, but what else can we do? */
157 asprintf(&user, "%s%s%s", p+1, lp_winbind_separator(), client);
159 user = strdup(client);
163 /* setup the string used by %U */
164 sub_set_smb_name(user);
166 reload_services(True);
168 /* the password is good - let them in */
169 pw = Get_Pwnam(user);
170 if (!pw && !strstr(user, lp_winbind_separator())) {
172 /* try it with a winbind domain prefix */
173 asprintf(&user2, "%s%s%s", lp_workgroup(), lp_winbind_separator(), user);
174 pw = Get_Pwnam(user2);
182 DEBUG(1,("Username %s is invalid on this system\n",user));
183 return ERROR_NT(NT_STATUS_NO_SUCH_USER);
186 if (!NT_STATUS_IS_OK(ret = make_server_info_pw(&server_info,pw))) {
187 DEBUG(1,("make_server_info_from_pw failed!\n"));
188 return ERROR_NT(ret);
191 sess_vuid = register_vuid(server_info, user);
194 free_server_info(&server_info);
196 if (sess_vuid == -1) {
197 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
200 set_message(outbuf,4,0,True);
201 SSVAL(outbuf, smb_vwv3, 0);
202 add_signature(outbuf);
204 SSVAL(outbuf,smb_uid,sess_vuid);
205 SSVAL(inbuf,smb_uid,sess_vuid);
207 return chain_reply(inbuf,outbuf,length,bufsize);
212 /****************************************************************************
213 send a security blob via a session setup reply
214 ****************************************************************************/
215 static BOOL reply_sesssetup_blob(connection_struct *conn, char *outbuf,
216 DATA_BLOB blob, NTSTATUS errcode)
220 set_message(outbuf,4,0,True);
222 /* we set NT_STATUS_MORE_PROCESSING_REQUIRED to tell the other end
223 that we aren't finished yet */
225 SIVAL(outbuf, smb_rcls, NT_STATUS_V(errcode));
226 SSVAL(outbuf, smb_vwv0, 0xFF); /* no chaining possible */
227 SSVAL(outbuf, smb_vwv3, blob.length);
229 memcpy(p, blob.data, blob.length);
231 p += srvstr_push(outbuf, p, "Unix", -1, STR_TERMINATE);
232 p += srvstr_push(outbuf, p, "Samba", -1, STR_TERMINATE);
233 p += srvstr_push(outbuf, p, lp_workgroup(), -1, STR_TERMINATE);
234 set_message_end(outbuf,p);
236 return send_smb(smbd_server_fd(),outbuf);
239 /****************************************************************************
240 send an NTLMSSP blob via a session setup reply, wrapped in SPNEGO
241 ****************************************************************************/
242 static BOOL reply_spnego_ntlmssp_blob(connection_struct *conn, char *outbuf,
243 DATA_BLOB *ntlmssp_blob, NTSTATUS errcode)
246 response = spnego_gen_auth_response(ntlmssp_blob);
247 reply_sesssetup_blob(conn, outbuf, response, errcode);
248 data_blob_free(&response);
252 /****************************************************************************
253 send an OK via a session setup reply, wrapped in SPNEGO.
254 get vuid and check first.
255 ****************************************************************************/
256 static BOOL reply_spnego_ntlmssp_ok(connection_struct *conn, char *outbuf,
257 AUTH_NTLMSSP_STATE *auth_ntlmssp_state)
261 DATA_BLOB null_blob = data_blob(NULL, 0);
263 sess_vuid = register_vuid(auth_ntlmssp_state->server_info, auth_ntlmssp_state->ntlmssp_state->user /* check this for weird */);
265 if (sess_vuid == -1) {
266 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
269 set_message(outbuf,4,0,True);
270 SSVAL(outbuf, smb_vwv3, 0);
272 if (auth_ntlmssp_state->server_info->guest) {
273 SSVAL(outbuf,smb_vwv2,1);
276 add_signature(outbuf);
278 SSVAL(outbuf,smb_uid,sess_vuid);
279 reply_spnego_ntlmssp_blob(conn, outbuf, &null_blob, NT_STATUS_OK);
283 /****************************************************************************
284 reply to a session setup spnego negotiate packet
285 ****************************************************************************/
286 static int reply_spnego_negotiate(connection_struct *conn,
289 int length, int bufsize,
292 char *OIDs[ASN1_MAX_OIDS];
295 DATA_BLOB chal, spnego_chal;
296 BOOL got_kerberos = False;
299 /* parse out the OIDs and the first sec blob */
300 if (!parse_negTokenTarg(blob1, OIDs, &secblob)) {
301 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
304 for (i=0;OIDs[i];i++) {
305 DEBUG(3,("Got OID %s\n", OIDs[i]));
306 if (strcmp(OID_KERBEROS5, OIDs[i]) == 0 ||
307 strcmp(OID_KERBEROS5_OLD, OIDs[i]) == 0) {
312 DEBUG(3,("Got secblob of size %d\n", secblob.length));
315 if (got_kerberos && (SEC_ADS == lp_security())) {
316 int ret = reply_spnego_kerberos(conn, inbuf, outbuf,
317 length, bufsize, &secblob);
318 data_blob_free(&secblob);
323 if (global_ntlmssp_state) {
324 auth_ntlmssp_end(&global_ntlmssp_state);
327 nt_status = auth_ntlmssp_start(&global_ntlmssp_state);
328 if (!NT_STATUS_IS_OK(nt_status)) {
329 return ERROR_NT(nt_status);
332 nt_status = auth_ntlmssp_update(global_ntlmssp_state,
335 data_blob_free(&secblob);
337 if (!NT_STATUS_IS_OK(nt_status)) {
338 nt_status = do_map_to_guest(nt_status,
339 &global_ntlmssp_state->server_info,
340 global_ntlmssp_state->ntlmssp_state->user,
341 global_ntlmssp_state->ntlmssp_state->domain);
344 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
345 if (!spnego_gen_challenge(&spnego_chal, &chal, NULL)) {
346 DEBUG(3,("Failed to generate challenge\n"));
347 data_blob_free(&chal);
348 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
351 /* now tell the client to send the auth packet */
352 reply_sesssetup_blob(conn, outbuf, spnego_chal, nt_status);
354 data_blob_free(&chal);
355 data_blob_free(&spnego_chal);
357 /* and tell smbd that we have already replied to this packet */
360 } else if (NT_STATUS_IS_OK(nt_status)) {
361 reply_spnego_ntlmssp_ok(conn, outbuf,
362 global_ntlmssp_state);
363 auth_ntlmssp_end(&global_ntlmssp_state);
364 data_blob_free(&chal);
366 /* and tell smbd that we have already replied to this packet */
370 auth_ntlmssp_end(&global_ntlmssp_state);
371 data_blob_free(&chal);
373 return ERROR_NT(nt_status_squash(nt_status));
377 /****************************************************************************
378 reply to a session setup spnego auth packet
379 ****************************************************************************/
380 static int reply_spnego_auth(connection_struct *conn, char *inbuf, char *outbuf,
381 int length, int bufsize,
384 DATA_BLOB auth, auth_reply;
387 if (!spnego_parse_auth(blob1, &auth)) {
389 file_save("auth.dat", blob1.data, blob1.length);
391 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
394 nt_status = auth_ntlmssp_update(global_ntlmssp_state,
397 data_blob_free(&auth);
398 data_blob_free(&auth_reply);
400 if (NT_STATUS_IS_OK(nt_status)) {
401 reply_spnego_ntlmssp_ok(conn, outbuf,
402 global_ntlmssp_state);
403 auth_ntlmssp_end(&global_ntlmssp_state);
405 } else { /* !NT_STATUS_IS_OK(nt_status) */
406 auth_ntlmssp_end(&global_ntlmssp_state);
407 return ERROR_NT(nt_status_squash(nt_status));
410 /* and tell smbd that we have already replied to this packet */
415 /****************************************************************************
416 reply to a session setup spnego anonymous packet
417 ****************************************************************************/
418 static int reply_spnego_anonymous(connection_struct *conn, char *inbuf, char *outbuf,
419 int length, int bufsize)
422 auth_serversupplied_info *server_info = NULL;
425 nt_status = check_guest_password(&server_info);
427 if (!NT_STATUS_IS_OK(nt_status)) {
428 return ERROR_NT(nt_status_squash(nt_status));
431 sess_vuid = register_vuid(server_info, lp_guestaccount());
433 free_server_info(&server_info);
435 if (sess_vuid == -1) {
436 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
439 set_message(outbuf,4,0,True);
440 SSVAL(outbuf, smb_vwv3, 0);
441 add_signature(outbuf);
443 SSVAL(outbuf,smb_uid,sess_vuid);
444 SSVAL(inbuf,smb_uid,sess_vuid);
446 return chain_reply(inbuf,outbuf,length,bufsize);
450 /****************************************************************************
451 reply to a session setup command
452 ****************************************************************************/
453 static int reply_sesssetup_and_X_spnego(connection_struct *conn, char *inbuf,char *outbuf,
454 int length,int bufsize)
460 DEBUG(3,("Doing spnego session setup\n"));
462 if (global_client_caps == 0) {
463 global_client_caps = IVAL(inbuf,smb_vwv10);
466 p = (uint8 *)smb_buf(inbuf);
468 if (SVAL(inbuf, smb_vwv7) == 0) {
469 /* an anonymous request */
470 return reply_spnego_anonymous(conn, inbuf, outbuf, length, bufsize);
473 /* pull the spnego blob */
474 blob1 = data_blob(p, SVAL(inbuf, smb_vwv7));
477 file_save("negotiate.dat", blob1.data, blob1.length);
480 if (blob1.data[0] == ASN1_APPLICATION(0)) {
481 /* its a negTokenTarg packet */
482 ret = reply_spnego_negotiate(conn, inbuf, outbuf, length, bufsize, blob1);
483 data_blob_free(&blob1);
487 if (blob1.data[0] == ASN1_CONTEXT(1)) {
488 /* its a auth packet */
489 ret = reply_spnego_auth(conn, inbuf, outbuf, length, bufsize, blob1);
490 data_blob_free(&blob1);
494 /* what sort of packet is this? */
495 DEBUG(1,("Unknown packet in reply_sesssetup_and_X_spnego\n"));
497 data_blob_free(&blob1);
499 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
503 /****************************************************************************
504 reply to a session setup command
505 ****************************************************************************/
506 int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,
507 int length,int bufsize)
513 DATA_BLOB plaintext_password;
515 fstring sub_user; /* Sainitised username for substituion */
518 fstring native_lanman;
519 static BOOL done_sesssetup = False;
520 extern BOOL global_encrypted_passwords_negotiated;
521 extern BOOL global_spnego_negotiated;
523 extern userdom_struct current_user_info;
526 auth_usersupplied_info *user_info = NULL;
527 extern struct auth_context *negprot_global_auth_context;
528 auth_serversupplied_info *server_info = NULL;
532 BOOL doencrypt = global_encrypted_passwords_negotiated;
534 START_PROFILE(SMBsesssetupX);
536 ZERO_STRUCT(lm_resp);
537 ZERO_STRUCT(nt_resp);
538 ZERO_STRUCT(plaintext_password);
540 DEBUG(3,("wct=%d flg2=0x%x\n", CVAL(inbuf, smb_wct), SVAL(inbuf, smb_flg2)));
542 /* a SPNEGO session setup has 12 command words, whereas a normal
543 NT1 session setup has 13. See the cifs spec. */
544 if (CVAL(inbuf, smb_wct) == 12 &&
545 (SVAL(inbuf, smb_flg2) & FLAGS2_EXTENDED_SECURITY)) {
546 if (!global_spnego_negotiated) {
547 DEBUG(0,("reply_sesssetup_and_X: Rejecting attempt at SPNEGO session setup when it was not negoitiated.\n"));
548 return ERROR_NT(NT_STATUS_UNSUCCESSFUL);
551 return reply_sesssetup_and_X_spnego(conn, inbuf, outbuf, length, bufsize);
554 smb_bufsize = SVAL(inbuf,smb_vwv2);
556 if (Protocol < PROTOCOL_NT1) {
557 uint16 passlen1 = SVAL(inbuf,smb_vwv7);
558 if ((passlen1 > MAX_PASS_LEN) || (passlen1 > smb_bufrem(inbuf, smb_buf(inbuf)))) {
559 return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
563 lm_resp = data_blob(smb_buf(inbuf), passlen1);
565 plaintext_password = data_blob(smb_buf(inbuf), passlen1+1);
566 /* Ensure null termination */
567 plaintext_password.data[passlen1] = 0;
570 srvstr_pull_buf(inbuf, user, smb_buf(inbuf)+passlen1, sizeof(user), STR_TERMINATE);
574 uint16 passlen1 = SVAL(inbuf,smb_vwv7);
575 uint16 passlen2 = SVAL(inbuf,smb_vwv8);
576 enum remote_arch_types ra_type = get_remote_arch();
577 char *p = smb_buf(inbuf);
579 if(global_client_caps == 0)
580 global_client_caps = IVAL(inbuf,smb_vwv11);
582 /* client_caps is used as final determination if client is NT or Win95.
583 This is needed to return the correct error codes in some
587 if(ra_type == RA_WINNT || ra_type == RA_WIN2K || ra_type == RA_WIN95) {
588 if(!(global_client_caps & (CAP_NT_SMBS | CAP_STATUS32))) {
589 set_remote_arch( RA_WIN95);
594 /* both Win95 and WinNT stuff up the password lengths for
595 non-encrypting systems. Uggh.
597 if passlen1==24 its a win95 system, and its setting the
598 password length incorrectly. Luckily it still works with the
599 default code because Win95 will null terminate the password
602 if passlen1>0 and passlen2>0 then maybe its a NT box and its
603 setting passlen2 to some random value which really stuffs
604 things up. we need to fix that one. */
606 if (passlen1 > 0 && passlen2 > 0 && passlen2 != 24 && passlen2 != 1)
610 /* check for nasty tricks */
611 if (passlen1 > MAX_PASS_LEN || passlen1 > smb_bufrem(inbuf, p)) {
612 return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
615 if (passlen2 > MAX_PASS_LEN || passlen2 > smb_bufrem(inbuf, p+passlen1)) {
616 return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
619 /* Save the lanman2 password and the NT md4 password. */
621 if ((doencrypt) && (passlen1 != 0) && (passlen1 != 24)) {
626 lm_resp = data_blob(p, passlen1);
627 nt_resp = data_blob(p+passlen1, passlen2);
630 srvstr_pull(inbuf, pass, smb_buf(inbuf),
631 sizeof(pass), passlen1, STR_TERMINATE);
632 plaintext_password = data_blob(pass, strlen(pass)+1);
635 p += passlen1 + passlen2;
636 p += srvstr_pull_buf(inbuf, user, p, sizeof(user), STR_TERMINATE);
637 p += srvstr_pull_buf(inbuf, domain, p, sizeof(domain), STR_TERMINATE);
638 p += srvstr_pull_buf(inbuf, native_os, p, sizeof(native_os), STR_TERMINATE);
639 p += srvstr_pull_buf(inbuf, native_lanman, p, sizeof(native_lanman), STR_TERMINATE);
640 DEBUG(3,("Domain=[%s] NativeOS=[%s] NativeLanMan=[%s]\n",
641 domain,native_os,native_lanman));
644 /* don't allow for weird usernames or domains */
645 alpha_strcpy(user, user, ". _-$", sizeof(user));
646 alpha_strcpy(domain, domain, ". _-@", sizeof(domain));
647 if (strstr(user, "..") || strstr(domain,"..")) {
648 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
651 DEBUG(3,("sesssetupX:name=[%s]\\[%s]@[%s]\n", domain, user, get_remote_machine_name()));
654 if (global_spnego_negotiated) {
656 /* This has to be here, becouse this is a perfectly valid behaviour for guest logons :-( */
658 DEBUG(0,("reply_sesssetup_and_X: Rejecting attempt at 'normal' session setup after negotiating spnego.\n"));
659 return ERROR_NT(NT_STATUS_UNSUCCESSFUL);
661 fstrcpy(sub_user, user);
663 /* setup the string used by %U */
664 sub_set_smb_name(user);
666 fstrcpy(sub_user, lp_guestaccount());
669 fstrcpy(current_user_info.smb_name,sub_user);
671 reload_services(True);
673 if (lp_security() == SEC_SHARE) {
674 /* in share level we should ignore any passwords */
676 data_blob_free(&lm_resp);
677 data_blob_free(&nt_resp);
678 data_blob_clear_free(&plaintext_password);
680 map_username(sub_user);
681 add_session_user(sub_user);
682 /* Then force it to null for the benfit of the code below */
688 nt_status = check_guest_password(&server_info);
690 } else if (doencrypt) {
691 if (!negprot_global_auth_context) {
692 DEBUG(0, ("reply_sesssetup_and_X: Attempted encrypted session setup without negprot denied!\n"));
693 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
695 nt_status = make_user_info_for_reply_enc(&user_info, user, domain,
697 if (NT_STATUS_IS_OK(nt_status)) {
698 nt_status = negprot_global_auth_context->check_ntlm_password(negprot_global_auth_context,
703 struct auth_context *plaintext_auth_context = NULL;
705 if (NT_STATUS_IS_OK(nt_status = make_auth_context_subsystem(&plaintext_auth_context))) {
706 chal = plaintext_auth_context->get_ntlm_challenge(plaintext_auth_context);
708 if (!make_user_info_for_reply(&user_info,
710 plaintext_password)) {
711 nt_status = NT_STATUS_NO_MEMORY;
714 if (NT_STATUS_IS_OK(nt_status)) {
715 nt_status = plaintext_auth_context->check_ntlm_password(plaintext_auth_context,
719 (plaintext_auth_context->free)(&plaintext_auth_context);
724 free_user_info(&user_info);
726 data_blob_free(&lm_resp);
727 data_blob_free(&nt_resp);
728 data_blob_clear_free(&plaintext_password);
730 if (!NT_STATUS_IS_OK(nt_status)) {
731 nt_status = do_map_to_guest(nt_status, &server_info, user, domain);
734 if (!NT_STATUS_IS_OK(nt_status)) {
735 return ERROR_NT(nt_status_squash(nt_status));
738 /* it's ok - setup a reply */
739 set_message(outbuf,3,0,True);
740 if (Protocol == PROTOCOL_NT1) {
741 add_signature(outbuf);
742 /* perhaps grab OS version here?? */
745 if (server_info->guest) {
746 SSVAL(outbuf,smb_vwv2,1);
749 /* register the name and uid as being validated, so further connections
750 to a uid can get through without a password, on the same VC */
752 sess_vuid = register_vuid(server_info, sub_user);
754 free_server_info(&server_info);
756 if (sess_vuid == -1) {
757 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
761 SSVAL(outbuf,smb_uid,sess_vuid);
762 SSVAL(inbuf,smb_uid,sess_vuid);
765 max_send = MIN(max_send,smb_bufsize);
767 done_sesssetup = True;
769 END_PROFILE(SMBsesssetupX);
770 return chain_reply(inbuf,outbuf,length,bufsize);