diff options
author | Andrew Tridgell <tridge@samba.org> | 2001-10-15 07:50:21 +0000 |
---|---|---|
committer | Andrew Tridgell <tridge@samba.org> | 2001-10-15 07:50:21 +0000 |
commit | 0c0dd06dbd558254ebb048223b0396454f7ee1dd (patch) | |
tree | db0c03b641899dc2842f9f8a5db89961e80e0d18 /source3 | |
parent | 59efa068bd3d2f920a40b3333d09a22beb8dedb3 (diff) | |
download | samba-0c0dd06dbd558254ebb048223b0396454f7ee1dd.tar.gz samba-0c0dd06dbd558254ebb048223b0396454f7ee1dd.tar.bz2 samba-0c0dd06dbd558254ebb048223b0396454f7ee1dd.zip |
split session setup code out of reply.c in preparation for adding
NTLMSSP and kerberos support in smbd
(This used to be commit 38a43d75e25bbebe0f6cdfcf389129a842ede842)
Diffstat (limited to 'source3')
-rw-r--r-- | source3/Makefile.in | 2 | ||||
-rw-r--r-- | source3/smbd/reply.c | 345 | ||||
-rw-r--r-- | source3/smbd/sesssetup.c | 355 |
3 files changed, 357 insertions, 345 deletions
diff --git a/source3/Makefile.in b/source3/Makefile.in index 9f4e48fc16..108c4f103e 100644 --- a/source3/Makefile.in +++ b/source3/Makefile.in @@ -189,7 +189,7 @@ SMBD_OBJ1 = smbd/server.o smbd/files.o smbd/chgpasswd.o smbd/connection.o \ smbd/dfree.o smbd/dir.o smbd/password.o smbd/conn.o smbd/fileio.o \ smbd/ipc.o smbd/lanman.o smbd/mangle.o smbd/negprot.o \ smbd/message.o smbd/nttrans.o smbd/pipes.o \ - smbd/reply.o smbd/trans2.o smbd/uid.o \ + smbd/reply.o smbd/sesssetup.o smbd/trans2.o smbd/uid.o \ smbd/dosmode.o smbd/filename.o smbd/open.o smbd/close.o \ smbd/blocking.o smbd/sec_ctx.o \ smbd/vfs.o smbd/vfs-wrap.o smbd/statcache.o \ diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c index 334a48e338..8b6e754549 100644 --- a/source3/smbd/reply.c +++ b/source3/smbd/reply.c @@ -44,20 +44,6 @@ unsigned int smb_echo_count = 0; extern fstring remote_machine; extern BOOL global_encrypted_passwords_negotiated; -/**************************************************************************** -report a possible attack via the password buffer overflow bug -****************************************************************************/ - -static void overflow_attack(int len) -{ - if( DEBUGLVL( 0 ) ) { - dbgtext( "ERROR: Invalid password length %d.\n", len ); - dbgtext( "Your machine may be under attack by someone " ); - dbgtext( "attempting to exploit an old bug.\n" ); - dbgtext( "Attack was from IP = %s.\n", client_addr() ); - } -} - /**************************************************************************** reply to an special message @@ -231,8 +217,7 @@ int reply_tcon_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt } if (passlen > MAX_PASS_LEN) { - overflow_attack(passlen); - return(ERROR_DOS(ERRDOS,ERRbuftoosmall)); + return ERROR_DOS(ERRDOS,ERRbuftoosmall); } memcpy(password,smb_buf(inbuf),passlen); @@ -373,334 +358,6 @@ int reply_ioctl(connection_struct *conn, } /**************************************************************************** -reply to a session setup command -****************************************************************************/ - -int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize) -{ - int sess_vuid; - gid_t gid; - uid_t uid; - char* full_name; - int smb_bufsize; - int smb_apasslen = 0; - pstring smb_apasswd; - int smb_ntpasslen = 0; - pstring smb_ntpasswd; - pstring user; - pstring orig_user; - fstring domain; - fstring native_os; - fstring native_lanman; - BOOL guest=False; - static BOOL done_sesssetup = False; - BOOL doencrypt = global_encrypted_passwords_negotiated; - START_PROFILE(SMBsesssetupX); - - *smb_apasswd = *smb_ntpasswd = 0; - - smb_bufsize = SVAL(inbuf,smb_vwv2); - - if (Protocol < PROTOCOL_NT1) { - smb_apasslen = SVAL(inbuf,smb_vwv7); - if (smb_apasslen > MAX_PASS_LEN) { - overflow_attack(smb_apasslen); - return(ERROR_DOS(ERRDOS,ERRbuftoosmall)); - } - - memcpy(smb_apasswd,smb_buf(inbuf),smb_apasslen); - srvstr_pull(inbuf, user, smb_buf(inbuf)+smb_apasslen, sizeof(user), -1, STR_TERMINATE); - - if (!doencrypt && (lp_security() != SEC_SERVER)) { - smb_apasslen = strlen(smb_apasswd); - } - } else { - uint16 passlen1 = SVAL(inbuf,smb_vwv7); - uint16 passlen2 = SVAL(inbuf,smb_vwv8); - enum remote_arch_types ra_type = get_remote_arch(); - char *p = smb_buf(inbuf); - - if(global_client_caps == 0) - global_client_caps = IVAL(inbuf,smb_vwv11); - - /* client_caps is used as final determination if client is NT or Win95. - This is needed to return the correct error codes in some - circumstances. - */ - - if(ra_type == RA_WINNT || ra_type == RA_WIN2K || ra_type == RA_WIN95) { - if(!(global_client_caps & (CAP_NT_SMBS | CAP_STATUS32))) { - set_remote_arch( RA_WIN95); - } - } - - if (passlen1 != 24 && passlen2 < 24) - doencrypt = False; - - if (passlen1 > MAX_PASS_LEN) { - overflow_attack(passlen1); - return ERROR_DOS(ERRDOS,ERRbuftoosmall); - } - - passlen1 = MIN(passlen1, MAX_PASS_LEN); - passlen2 = MIN(passlen2, MAX_PASS_LEN); - - if (!doencrypt) { - /* both Win95 and WinNT stuff up the password lengths for - non-encrypting systems. Uggh. - - if passlen1==24 its a win95 system, and its setting the - password length incorrectly. Luckily it still works with the - default code because Win95 will null terminate the password - anyway - - if passlen1>0 and passlen2>0 then maybe its a NT box and its - setting passlen2 to some random value which really stuffs - things up. we need to fix that one. */ - - if (passlen1 > 0 && passlen2 > 0 && passlen2 != 24 && passlen2 != 1) - passlen2 = 0; - } - - if (lp_restrict_anonymous()) { - /* there seems to be no reason behind the differences in MS clients formatting - * various info like the domain, NativeOS, and NativeLanMan fields. Win95 - * in particular seems to have an extra null byte between the username and the - * domain, or the password length calculation is wrong, which throws off the - * string extraction routines below. This makes the value of domain be the - * empty string, which fails the restrict anonymous check further down. - * This compensates for that, and allows browsing to work in mixed NT and - * win95 environments even when restrict anonymous is true. AAB - */ - dump_data(100, p, 0x70); - DEBUG(9, ("passlen1=%d, passlen2=%d\n", passlen1, passlen2)); - if (ra_type == RA_WIN95 && !passlen1 && !passlen2 && p[0] == 0 && p[1] == 0) { - DEBUG(0, ("restrict anonymous parameter used in a win95 environment!\n")); - DEBUG(0, ("client is win95 and broken passlen1 offset -- attempting fix\n")); - DEBUG(0, ("if win95 cilents are having difficulty browsing, you will be unable to use restrict anonymous\n")); - passlen1 = 1; - } - } - - /* Save the lanman2 password and the NT md4 password. */ - smb_apasslen = passlen1; - memcpy(smb_apasswd,p,smb_apasslen); - - smb_ntpasslen = passlen2; - memcpy(smb_ntpasswd,p+passlen1,smb_ntpasslen); - - if (smb_apasslen != 24 || !doencrypt) { - /* trim the password */ - smb_apasslen = strlen(smb_apasswd); - - /* wfwg sometimes uses a space instead of a null */ - if (strequal(smb_apasswd," ")) { - smb_apasslen = 0; - *smb_apasswd = 0; - } - } - - p += passlen1 + passlen2; - p += srvstr_pull(inbuf, user, p, sizeof(user), -1, - STR_TERMINATE); - /* - * Incoming user and domain are in DOS codepage format. Convert - * to UNIX. - */ - p += srvstr_pull(inbuf, domain, p, sizeof(domain), - -1, STR_TERMINATE); - p += srvstr_pull(inbuf, native_os, p, sizeof(native_os), - -1, STR_TERMINATE); - p += srvstr_pull(inbuf, native_lanman, p, sizeof(native_lanman), - -1, STR_TERMINATE); - DEBUG(3,("Domain=[%s] NativeOS=[%s] NativeLanMan=[%s]\n", - domain,native_os,native_lanman)); - } - - /* don't allow for weird usernames or domains */ - alpha_strcpy(user, user, ". _-$", sizeof(user)); - alpha_strcpy(domain, domain, ". _-", sizeof(domain)); - if (strstr(user, "..") || strstr(domain,"..")) { - return ERROR_NT(NT_STATUS_LOGON_FAILURE); - } - - if (lp_security() == SEC_SHARE) { - /* in share level we should ignore any passwords */ - smb_ntpasslen = 0; - smb_apasslen = 0; - guest = True; - } - - - DEBUG(3,("sesssetupX:name=[%s]\\[%s]@[%s]\n",user, domain, remote_machine)); - - if (done_sesssetup && lp_restrict_anonymous()) { - /* tests show that even if browsing is done over already validated connections - * without a username and password the domain is still provided, which it - * wouldn't be if it was a purely anonymous connection. So, in order to - * restrict anonymous, we only deny connections that have no session - * information. If a domain has been provided, then it's not a purely - * anonymous connection. AAB - */ - if (!*user && !*smb_apasswd && !*domain) { - DEBUG(0, ("restrict anonymous is True and anonymous connection attempted. Denying access.\n")); - END_PROFILE(SMBsesssetupX); - return ERROR_DOS(ERRDOS,ERRnoaccess); - } - } - - /* If no username is sent use the guest account */ - if (!*user) { - pstrcpy(user,lp_guestaccount(-1)); - guest = True; - } - - pstrcpy(current_user_info.smb_name,user); - - reload_services(True); - - /* - * Save the username before mapping. We will use - * the original username sent to us for security=server - * and security=domain checking. - */ - - pstrcpy( orig_user, user); - - /* - * Always try the "DOMAIN\user" lookup first, as this is the most - * specific case. If this fails then try the simple "user" lookup. - * But don't do this for guests, as this is always a local user. - */ - - if (!guest) { - pstring dom_user; - - /* Work out who's who */ - - slprintf(dom_user, sizeof(dom_user) - 1,"%s%s%s", - domain, lp_winbind_separator(), user); - - if (sys_getpwnam(dom_user) != NULL) { - pstrcpy(user, dom_user); - DEBUG(3,("Using unix username %s\n", dom_user)); - } - - /* - * Pass the user through the NT -> unix user mapping - * function. - */ - - (void)map_username(user); - - /* - * Do any UNIX username case mangling. - */ - smb_getpwnam(user, True); - } - - add_session_user(user); - - if (!guest) { - NTSTATUS nt_status; - nt_status = pass_check_smb(orig_user, user, - domain, remote_machine, - (unsigned char *)smb_apasswd, - smb_apasslen, - (unsigned char *)smb_ntpasswd, - smb_ntpasslen); - - if NT_STATUS_IS_OK(nt_status) { - - } else if NT_STATUS_EQUAL(nt_status, NT_STATUS_NO_SUCH_USER) { - if ((lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_USER) || - (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD)) { - DEBUG(3,("No such user %s [%s] - using guest account\n",user, domain)); - pstrcpy(user,lp_guestaccount(-1)); - guest = True; - } else { - /* Match WinXP and don't give the game away */ - return ERROR_NT(NT_STATUS_LOGON_FAILURE); - } - } else if NT_STATUS_EQUAL(nt_status, NT_STATUS_WRONG_PASSWORD) { - if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD) { - pstrcpy(user,lp_guestaccount(-1)); - DEBUG(3,("Registered username %s for guest access\n",user)); - guest = True; - } else { - /* Match WinXP and don't give the game away */ - return ERROR_NT(NT_STATUS_LOGON_FAILURE); - } - } else { - return ERROR_NT(nt_status); - } - } - - if (!strequal(user,lp_guestaccount(-1)) && - lp_servicenumber(user) < 0) - { - add_home_service(user,get_user_home_dir(user)); - } - - - /* it's ok - setup a reply */ - if (Protocol < PROTOCOL_NT1) { - set_message(outbuf,3,0,True); - } else { - char *p; - set_message(outbuf,3,0,True); - p = smb_buf(outbuf); - p += srvstr_push(outbuf, p, "Unix", -1, STR_TERMINATE); - p += srvstr_push(outbuf, p, "Samba", -1, STR_TERMINATE); - p += srvstr_push(outbuf, p, lp_workgroup(), -1, STR_TERMINATE); - set_message_end(outbuf,p); - /* perhaps grab OS version here?? */ - } - - /* Set the correct uid in the outgoing and incoming packets - We will use this on future requests to determine which - user we should become. - */ - { - const struct passwd *pw = smb_getpwnam(user,False); - if (!pw) { - DEBUG(1,("Username %s is invalid on this system\n",user)); - END_PROFILE(SMBsesssetupX); - return ERROR_NT(NT_STATUS_LOGON_FAILURE); - } - gid = pw->pw_gid; - uid = pw->pw_uid; - full_name = pw->pw_gecos; - } - - if (guest) - SSVAL(outbuf,smb_vwv2,1); - - /* register the name and uid as being validated, so further connections - to a uid can get through without a password, on the same VC */ - - sess_vuid = register_vuid(uid,gid,user,orig_user,domain,guest, full_name); - - if (sess_vuid == -1) { - return ERROR_NT(NT_STATUS_LOGON_FAILURE); - } - - - SSVAL(outbuf,smb_uid,sess_vuid); - SSVAL(inbuf,smb_uid,sess_vuid); - - if (!done_sesssetup) - max_send = MIN(max_send,smb_bufsize); - - DEBUG(6,("Client requested max send size of %d\n", max_send)); - - done_sesssetup = True; - - END_PROFILE(SMBsesssetupX); - return chain_reply(inbuf,outbuf,length,bufsize); -} - -/**************************************************************************** reply to a chkpth ****************************************************************************/ int reply_chkpth(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize) diff --git a/source3/smbd/sesssetup.c b/source3/smbd/sesssetup.c new file mode 100644 index 0000000000..45fa2d6a4a --- /dev/null +++ b/source3/smbd/sesssetup.c @@ -0,0 +1,355 @@ +/* + Unix SMB/Netbios implementation. + Version 3.0 + handle SMBsessionsetup + Copyright (C) Andrew Tridgell 1998-2001 + Copyright (C) Andrew Bartlett 2001 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" + +/**************************************************************************** +reply to a session setup command +****************************************************************************/ +int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf, + int length,int bufsize) +{ + int sess_vuid; + gid_t gid; + uid_t uid; + char* full_name; + int smb_bufsize; + int smb_apasslen = 0; + pstring smb_apasswd; + int smb_ntpasslen = 0; + pstring smb_ntpasswd; + pstring user; + pstring orig_user; + fstring domain; + fstring native_os; + fstring native_lanman; + BOOL guest=False; + static BOOL done_sesssetup = False; + extern BOOL global_encrypted_passwords_negotiated; + extern uint32 global_client_caps; + extern int Protocol; + extern fstring remote_machine; + extern userdom_struct current_user_info; + extern int max_send; + BOOL doencrypt = global_encrypted_passwords_negotiated; + START_PROFILE(SMBsesssetupX); + + *smb_apasswd = *smb_ntpasswd = 0; + + smb_bufsize = SVAL(inbuf,smb_vwv2); + + if (Protocol < PROTOCOL_NT1) { + smb_apasslen = SVAL(inbuf,smb_vwv7); + if (smb_apasslen > MAX_PASS_LEN) { + return ERROR_DOS(ERRDOS,ERRbuftoosmall); + } + + memcpy(smb_apasswd,smb_buf(inbuf),smb_apasslen); + srvstr_pull(inbuf, user, smb_buf(inbuf)+smb_apasslen, sizeof(user), -1, STR_TERMINATE); + + if (!doencrypt && (lp_security() != SEC_SERVER)) { + smb_apasslen = strlen(smb_apasswd); + } + } else { + uint16 passlen1 = SVAL(inbuf,smb_vwv7); + uint16 passlen2 = SVAL(inbuf,smb_vwv8); + enum remote_arch_types ra_type = get_remote_arch(); + char *p = smb_buf(inbuf); + + if(global_client_caps == 0) + global_client_caps = IVAL(inbuf,smb_vwv11); + + /* client_caps is used as final determination if client is NT or Win95. + This is needed to return the correct error codes in some + circumstances. + */ + + if(ra_type == RA_WINNT || ra_type == RA_WIN2K || ra_type == RA_WIN95) { + if(!(global_client_caps & (CAP_NT_SMBS | CAP_STATUS32))) { + set_remote_arch( RA_WIN95); + } + } + + if (passlen1 != 24 && passlen2 < 24) + doencrypt = False; + + if (passlen1 > MAX_PASS_LEN) { + return ERROR_DOS(ERRDOS,ERRbuftoosmall); + } + + passlen1 = MIN(passlen1, MAX_PASS_LEN); + passlen2 = MIN(passlen2, MAX_PASS_LEN); + + if (!doencrypt) { + /* both Win95 and WinNT stuff up the password lengths for + non-encrypting systems. Uggh. + + if passlen1==24 its a win95 system, and its setting the + password length incorrectly. Luckily it still works with the + default code because Win95 will null terminate the password + anyway + + if passlen1>0 and passlen2>0 then maybe its a NT box and its + setting passlen2 to some random value which really stuffs + things up. we need to fix that one. */ + + if (passlen1 > 0 && passlen2 > 0 && passlen2 != 24 && passlen2 != 1) + passlen2 = 0; + } + + if (lp_restrict_anonymous()) { + /* there seems to be no reason behind the + * differences in MS clients formatting + * various info like the domain, NativeOS, and + * NativeLanMan fields. Win95 in particular + * seems to have an extra null byte between + * the username and the domain, or the + * password length calculation is wrong, which + * throws off the string extraction routines + * below. This makes the value of domain be + * the empty string, which fails the restrict + * anonymous check further down. This + * compensates for that, and allows browsing + * to work in mixed NT and win95 environments + * even when restrict anonymous is true. AAB + * */ + dump_data(100, p, 0x70); + DEBUG(9, ("passlen1=%d, passlen2=%d\n", passlen1, passlen2)); + if (ra_type == RA_WIN95 && !passlen1 && !passlen2 && p[0] == 0 && p[1] == 0) { + DEBUG(0, ("restrict anonymous parameter used in a win95 environment!\n")); + DEBUG(0, ("client is win95 and broken passlen1 offset -- attempting fix\n")); + DEBUG(0, ("if win95 cilents are having difficulty browsing, you will be unable to use restrict anonymous\n")); + passlen1 = 1; + } + } + + /* Save the lanman2 password and the NT md4 password. */ + smb_apasslen = passlen1; + memcpy(smb_apasswd,p,smb_apasslen); + + smb_ntpasslen = passlen2; + memcpy(smb_ntpasswd,p+passlen1,smb_ntpasslen); + + if (smb_apasslen != 24 || !doencrypt) { + /* trim the password */ + smb_apasslen = strlen(smb_apasswd); + + /* wfwg sometimes uses a space instead of a null */ + if (strequal(smb_apasswd," ")) { + smb_apasslen = 0; + *smb_apasswd = 0; + } + } + + p += passlen1 + passlen2; + p += srvstr_pull(inbuf, user, p, sizeof(user), -1, + STR_TERMINATE); + p += srvstr_pull(inbuf, domain, p, sizeof(domain), + -1, STR_TERMINATE); + p += srvstr_pull(inbuf, native_os, p, sizeof(native_os), + -1, STR_TERMINATE); + p += srvstr_pull(inbuf, native_lanman, p, sizeof(native_lanman), + -1, STR_TERMINATE); + DEBUG(3,("Domain=[%s] NativeOS=[%s] NativeLanMan=[%s]\n", + domain,native_os,native_lanman)); + } + + /* don't allow for weird usernames or domains */ + alpha_strcpy(user, user, ". _-$", sizeof(user)); + alpha_strcpy(domain, domain, ". _-", sizeof(domain)); + if (strstr(user, "..") || strstr(domain,"..")) { + return ERROR_NT(NT_STATUS_LOGON_FAILURE); + } + + if (lp_security() == SEC_SHARE) { + /* in share level we should ignore any passwords */ + smb_ntpasslen = 0; + smb_apasslen = 0; + guest = True; + } + + + DEBUG(3,("sesssetupX:name=[%s]\\[%s]@[%s]\n",user, domain, remote_machine)); + + if (done_sesssetup && lp_restrict_anonymous()) { + /* tests show that even if browsing is done over + * already validated connections without a username + * and password the domain is still provided, which it + * wouldn't be if it was a purely anonymous + * connection. So, in order to restrict anonymous, we + * only deny connections that have no session + * information. If a domain has been provided, then + * it's not a purely anonymous connection. AAB */ + if (!*user && !*smb_apasswd && !*domain) { + DEBUG(0, ("restrict anonymous is True and anonymous connection attempted. Denying access.\n")); + END_PROFILE(SMBsesssetupX); + return ERROR_DOS(ERRDOS,ERRnoaccess); + } + } + + /* If no username is sent use the guest account */ + if (!*user) { + pstrcpy(user,lp_guestaccount(-1)); + guest = True; + } + + pstrcpy(current_user_info.smb_name,user); + + reload_services(True); + + /* + * Save the username before mapping. We will use + * the original username sent to us for security=server + * and security=domain checking. + */ + + pstrcpy( orig_user, user); + + /* + * Always try the "DOMAIN\user" lookup first, as this is the most + * specific case. If this fails then try the simple "user" lookup. + * But don't do this for guests, as this is always a local user. + */ + + if (!guest) { + pstring dom_user; + + /* Work out who's who */ + + slprintf(dom_user, sizeof(dom_user) - 1,"%s%s%s", + domain, lp_winbind_separator(), user); + + if (sys_getpwnam(dom_user) != NULL) { + pstrcpy(user, dom_user); + DEBUG(3,("Using unix username %s\n", dom_user)); + } + + /* + * Pass the user through the NT -> unix user mapping + * function. + */ + + (void)map_username(user); + + /* + * Do any UNIX username case mangling. + */ + smb_getpwnam(user, True); + } + + add_session_user(user); + + if (!guest) { + NTSTATUS nt_status; + nt_status = pass_check_smb(orig_user, user, + domain, remote_machine, + (unsigned char *)smb_apasswd, + smb_apasslen, + (unsigned char *)smb_ntpasswd, + smb_ntpasslen); + + if NT_STATUS_IS_OK(nt_status) { + + } else if NT_STATUS_EQUAL(nt_status, NT_STATUS_NO_SUCH_USER) { + if ((lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_USER) || + (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD)) { + DEBUG(3,("No such user %s [%s] - using guest account\n",user, domain)); + pstrcpy(user,lp_guestaccount(-1)); + guest = True; + } else { + /* Match WinXP and don't give the game away */ + return ERROR_NT(NT_STATUS_LOGON_FAILURE); + } + } else if NT_STATUS_EQUAL(nt_status, NT_STATUS_WRONG_PASSWORD) { + if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD) { + pstrcpy(user,lp_guestaccount(-1)); + DEBUG(3,("Registered username %s for guest access\n",user)); + guest = True; + } else { + /* Match WinXP and don't give the game away */ + return ERROR_NT(NT_STATUS_LOGON_FAILURE); + } + } else { + return ERROR_NT(nt_status); + } + } + + if (!strequal(user,lp_guestaccount(-1)) && + lp_servicenumber(user) < 0) { + add_home_service(user,get_user_home_dir(user)); + } + + + /* it's ok - setup a reply */ + if (Protocol < PROTOCOL_NT1) { + set_message(outbuf,3,0,True); + } else { + char *p; + set_message(outbuf,3,0,True); + p = smb_buf(outbuf); + p += srvstr_push(outbuf, p, "Unix", -1, STR_TERMINATE); + p += srvstr_push(outbuf, p, "Samba", -1, STR_TERMINATE); + p += srvstr_push(outbuf, p, lp_workgroup(), -1, STR_TERMINATE); + set_message_end(outbuf,p); + /* perhaps grab OS version here?? */ + } + + /* Set the correct uid in the outgoing and incoming packets + We will use this on future requests to determine which + user we should become. + */ + { + const struct passwd *pw = smb_getpwnam(user,False); + if (!pw) { + DEBUG(1,("Username %s is invalid on this system\n",user)); + END_PROFILE(SMBsesssetupX); + return ERROR_NT(NT_STATUS_LOGON_FAILURE); + } + gid = pw->pw_gid; + uid = pw->pw_uid; + full_name = pw->pw_gecos; + } + + if (guest) + SSVAL(outbuf,smb_vwv2,1); + + /* register the name and uid as being validated, so further connections + to a uid can get through without a password, on the same VC */ + + sess_vuid = register_vuid(uid,gid,user,orig_user,domain,guest, full_name); + + if (sess_vuid == -1) { + return ERROR_NT(NT_STATUS_LOGON_FAILURE); + } + + + SSVAL(outbuf,smb_uid,sess_vuid); + SSVAL(inbuf,smb_uid,sess_vuid); + + if (!done_sesssetup) + max_send = MIN(max_send,smb_bufsize); + + done_sesssetup = True; + + END_PROFILE(SMBsesssetupX); + return chain_reply(inbuf,outbuf,length,bufsize); +} |