summaryrefslogtreecommitdiff
path: root/source3
diff options
context:
space:
mode:
authorAndrew Tridgell <tridge@samba.org>2001-10-15 07:50:21 +0000
committerAndrew Tridgell <tridge@samba.org>2001-10-15 07:50:21 +0000
commit0c0dd06dbd558254ebb048223b0396454f7ee1dd (patch)
treedb0c03b641899dc2842f9f8a5db89961e80e0d18 /source3
parent59efa068bd3d2f920a40b3333d09a22beb8dedb3 (diff)
downloadsamba-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.in2
-rw-r--r--source3/smbd/reply.c345
-rw-r--r--source3/smbd/sesssetup.c355
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);
+}