summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source3/Makefile.in7
-rw-r--r--source3/auth/auth.c83
-rw-r--r--source3/auth/auth_domain.c374
-rw-r--r--source3/auth/auth_rhosts.c21
-rw-r--r--source3/auth/auth_sam.c10
-rw-r--r--source3/auth/auth_unix.c85
-rw-r--r--source3/include/auth.h4
-rw-r--r--source3/libsmb/domain_client_validate.c363
-rw-r--r--source3/nsswitch/winbindd_pam.c15
-rw-r--r--source3/rpc_client/cli_login.c18
-rw-r--r--source3/rpc_server/srv_netlog_nt.c25
-rw-r--r--source3/smbd/auth.c83
-rw-r--r--source3/smbd/auth_domain.c374
-rw-r--r--source3/smbd/auth_rhosts.c21
-rw-r--r--source3/smbd/auth_smbpasswd.c10
-rw-r--r--source3/smbd/auth_unix.c85
16 files changed, 702 insertions, 876 deletions
diff --git a/source3/Makefile.in b/source3/Makefile.in
index 63a2543e44..d9dc423724 100644
--- a/source3/Makefile.in
+++ b/source3/Makefile.in
@@ -165,7 +165,8 @@ RPC_CLIENT_OBJ = rpc_client/cli_netlogon.o rpc_client/cli_pipe.o \
rpc_client/cli_lsarpc.o rpc_client/cli_connect.o \
rpc_client/cli_use.o rpc_client/cli_login.o \
rpc_client/cli_spoolss_notify.o rpc_client/ncacn_np_use.o \
- lib/util_list.o rpc_client/cli_trust.o
+ lib/util_list.o rpc_client/cli_trust.o \
+ libsmb/domain_client_validate.o
LOCKING_OBJ = locking/locking.o locking/brlock.o locking/posix.o
@@ -185,7 +186,7 @@ OPLOCK_OBJ = smbd/oplock.o smbd/oplock_irix.o smbd/oplock_linux.o
NOTIFY_OBJ = smbd/notify.o smbd/notify_hash.o smbd/notify_kernel.o
AUTH_OBJ = smbd/auth.o smbd/auth_smbpasswd.o smbd/auth_server.o smbd/auth_domain.o \
- smbd/auth_rhosts.o smbd/auth_util.o
+ smbd/auth_rhosts.o smbd/auth_unix.o smbd/auth_util.o
SMBD_OBJ1 = smbd/server.o smbd/files.o smbd/chgpasswd.o smbd/connection.o \
smbd/utmp.o smbd/session.o \
@@ -386,7 +387,7 @@ WINBINDD_OBJ1 = \
nsswitch/winbindd_misc.o
NECESSARY_BECAUSE_SAMBA_DEPENDENCIES_ARE_SO_BROKEN_OBJ = \
- smbd/auth_domain.o \
+ libsmb/domain_client_validate.o \
rpc_client/cli_netlogon.o rpc_client/cli_login.o
WINBINDD_OBJ = \
diff --git a/source3/auth/auth.c b/source3/auth/auth.c
index 94008e4d00..bbcf34e8ca 100644
--- a/source3/auth/auth.c
+++ b/source3/auth/auth.c
@@ -27,46 +27,6 @@ extern int DEBUGLEVEL;
extern pstring global_myname;
-
-/****************************************************************************
-update the encrypted smbpasswd file from the plaintext username and password
-
-this ugly hack needs to die, but not quite yet...
-*****************************************************************************/
-static BOOL update_smbpassword_file(char *user, char *password)
-{
- SAM_ACCOUNT *sampass = NULL;
- BOOL ret;
-
- pdb_init_sam(&sampass);
-
- become_root();
- ret = pdb_getsampwnam(sampass, user);
- unbecome_root();
-
- if(ret == False) {
- DEBUG(0,("update_smbpassword_file: pdb_getsampwnam failed to locate %s\n", user));
- pdb_free_sam(sampass);
- return False;
- }
-
- /*
- * Remove the account disabled flag - we are updating the
- * users password from a login.
- */
- pdb_set_acct_ctrl(sampass, pdb_get_acct_ctrl(sampass) & ~ACB_DISABLED);
-
- /* Here, the flag is one, because we want to ignore the
- XXXXXXX'd out password */
- ret = change_oem_password( sampass, password, True);
- if (ret == False) {
- DEBUG(3,("change_oem_password returned False\n"));
- }
-
- pdb_free_sam(sampass);
- return ret;
-}
-
/****************************************************************************
Check user is in correct domain if required
****************************************************************************/
@@ -88,21 +48,29 @@ static BOOL check_domain_match(char *user, char *domain)
}
}
+/****************************************************************************
+ Check a users password, as given in the user-info struct and return various
+ interesting details in the server_info struct.
+
+ This functions does NOT need to be in a become_root()/unbecome_root() pair
+ as it makes the calls itself when needed.
+****************************************************************************/
uint32 check_password(const auth_usersupplied_info *user_info, auth_serversupplied_info *server_info)
{
uint32 nt_status = NT_STATUS_LOGON_FAILURE;
-
+ BOOL done_pam = False;
+
DEBUG(3, ("check_password: Checking password for user %s with the new password interface\n", user_info->smb_username.str));
- if (check_hosts_equiv(user_info->smb_username.str)) {
- nt_status = NT_STATUS_NOPROBLEMO;
- }
-
if (!check_domain_match(user_info->smb_username.str, user_info->domain.str)) {
return NT_STATUS_LOGON_FAILURE;
}
+ if (nt_status != NT_STATUS_NOPROBLEMO) {
+ nt_status = check_rhosts_security(user_info, server_info);
+ }
+
if ((lp_security() == SEC_DOMAIN) && (nt_status != NT_STATUS_NOPROBLEMO)) {
nt_status = check_domain_security(user_info, server_info);
}
@@ -115,28 +83,23 @@ uint32 check_password(const auth_usersupplied_info *user_info, auth_serversuppli
smb_user_control(user_info->smb_username.str, nt_status);
}
- if ((nt_status != NT_STATUS_NOPROBLEMO)
- && (user_info->plaintext_password.len > 0)
- && (!lp_plaintext_to_smbpasswd())) {
- return (pass_check(user_info->smb_username.str,
- user_info->plaintext_password.str,
- user_info->plaintext_password.len,
- lp_update_encrypted() ?
- update_smbpassword_file : NULL)
- ? NT_STATUS_NOPROBLEMO : NT_STATUS_LOGON_FAILURE);
- }
-
if (nt_status != NT_STATUS_NOPROBLEMO) {
- nt_status = check_smbpasswd_security(user_info, server_info);
+ if ((user_info->plaintext_password.len > 0)
+ && (!lp_plaintext_to_smbpasswd())) {
+ nt_status = check_unix_security(user_info, server_info);
+ done_pam = True;
+ } else {
+ nt_status = check_smbpasswd_security(user_info, server_info);
+ }
}
-
- if (nt_status == NT_STATUS_NOPROBLEMO) {
+
+ if ((nt_status == NT_STATUS_NOPROBLEMO) && !done_pam) {
/* We might not be root if we are an RPC call */
become_root();
nt_status = smb_pam_accountcheck(user_info->smb_username.str);
unbecome_root();
}
-
+
if (nt_status == NT_STATUS_NOPROBLEMO) {
DEBUG(5, ("check_password: Password for user %s suceeded\n", user_info->smb_username.str));
} else {
diff --git a/source3/auth/auth_domain.c b/source3/auth/auth_domain.c
index e94ea13edc..a2e3c7a9b5 100644
--- a/source3/auth/auth_domain.c
+++ b/source3/auth/auth_domain.c
@@ -23,289 +23,39 @@
#include "includes.h"
extern int DEBUGLEVEL;
-extern struct in_addr ipzero;
BOOL global_machine_password_needs_changing = False;
-extern pstring global_myname;
-
-/***********************************************************************
- Connect to a remote machine for domain security authentication
- given a name or IP address.
- ***********************************************************************/
-
-static BOOL connect_to_domain_password_server(struct cli_state *pcli,
- char *server, unsigned char *trust_passwd)
-{
- struct in_addr dest_ip;
- fstring remote_machine;
-
- if(cli_initialise(pcli) == NULL) {
- DEBUG(0,("connect_to_domain_password_server: unable to initialize client connection.\n"));
- return False;
- }
-
- if (is_ipaddress(server)) {
- struct in_addr to_ip;
-
- /* we shouldn't have 255.255.255.255 forthe IP address of
- a password server anyways */
- if ((to_ip.s_addr=inet_addr(server)) == 0xFFFFFFFF) {
- DEBUG (0,("connect_to_domain_password_server: inet_addr(%s) returned 0xFFFFFFFF!\n", server));
- return False;
- }
-
- if (!name_status_find(0x20, to_ip, remote_machine)) {
- DEBUG(0, ("connect_to_domain_password_server: Can't "
- "resolve name for IP %s\n", server));
- return False;
- }
- } else {
- fstrcpy(remote_machine, server);
- }
-
- standard_sub_basic(remote_machine);
- strupper(remote_machine);
-
- if(!resolve_name( remote_machine, &dest_ip, 0x20)) {
- DEBUG(1,("connect_to_domain_password_server: Can't resolve address for %s\n", remote_machine));
- cli_shutdown(pcli);
- return False;
- }
-
- if (ismyip(dest_ip)) {
- DEBUG(1,("connect_to_domain_password_server: Password server loop - not using password server %s\n",
- remote_machine));
- cli_shutdown(pcli);
- return False;
- }
-
- if (!cli_connect(pcli, remote_machine, &dest_ip)) {
- DEBUG(0,("connect_to_domain_password_server: unable to connect to SMB server on \
-machine %s. Error was : %s.\n", remote_machine, cli_errstr(pcli) ));
- cli_shutdown(pcli);
- return False;
- }
-
- if (!attempt_netbios_session_request(pcli, global_myname, remote_machine, &dest_ip)) {
- DEBUG(0,("connect_to_password_server: machine %s rejected the NetBIOS \
-session request. Error was : %s.\n", remote_machine, cli_errstr(pcli) ));
- return False;
- }
-
- pcli->protocol = PROTOCOL_NT1;
-
- if (!cli_negprot(pcli)) {
- DEBUG(0,("connect_to_domain_password_server: machine %s rejected the negotiate protocol. \
-Error was : %s.\n", remote_machine, cli_errstr(pcli) ));
- cli_shutdown(pcli);
- return False;
- }
-
- if (pcli->protocol != PROTOCOL_NT1) {
- DEBUG(0,("connect_to_domain_password_server: machine %s didn't negotiate NT protocol.\n",
- remote_machine));
- cli_shutdown(pcli);
- return False;
- }
-
- /*
- * Do an anonymous session setup.
- */
-
- if (!cli_session_setup(pcli, "", "", 0, "", 0, "")) {
- DEBUG(0,("connect_to_domain_password_server: machine %s rejected the session setup. \
-Error was : %s.\n", remote_machine, cli_errstr(pcli) ));
- cli_shutdown(pcli);
- return False;
- }
-
- if (!(pcli->sec_mode & 1)) {
- DEBUG(1,("connect_to_domain_password_server: machine %s isn't in user level security mode\n",
- remote_machine));
- cli_shutdown(pcli);
- return False;
- }
-
- if (!cli_send_tconX(pcli, "IPC$", "IPC", "", 1)) {
- DEBUG(0,("connect_to_domain_password_server: machine %s rejected the tconX on the IPC$ share. \
-Error was : %s.\n", remote_machine, cli_errstr(pcli) ));
- cli_shutdown(pcli);
- return False;
- }
-
- /*
- * We now have an anonymous connection to IPC$ on the domain password server.
- */
-
- /*
- * Even if the connect succeeds we need to setup the netlogon
- * pipe here. We do this as we may just have changed the domain
- * account password on the PDC and yet we may be talking to
- * a BDC that doesn't have this replicated yet. In this case
- * a successful connect to a DC needs to take the netlogon connect
- * into account also. This patch from "Bjart Kvarme" <bjart.kvarme@usit.uio.no>.
- */
-
- if(cli_nt_session_open(pcli, PIPE_NETLOGON) == False) {
- DEBUG(0,("connect_to_domain_password_server: unable to open the domain client session to \
-machine %s. Error was : %s.\n", remote_machine, cli_errstr(pcli)));
- cli_nt_session_close(pcli);
- cli_ulogoff(pcli);
- cli_shutdown(pcli);
- return False;
- }
-
- if (cli_nt_setup_creds(pcli, trust_passwd) == False) {
- DEBUG(0,("connect_to_domain_password_server: unable to setup the PDC credentials to machine \
-%s. Error was : %s.\n", remote_machine, cli_errstr(pcli)));
- cli_nt_session_close(pcli);
- cli_ulogoff(pcli);
- cli_shutdown(pcli);
- return(False);
- }
-
- return True;
-}
-
-/***********************************************************************
- Utility function to attempt a connection to an IP address of a DC.
-************************************************************************/
-
-static BOOL attempt_connect_to_dc(struct cli_state *pcli, struct in_addr *ip,
- unsigned char *trust_passwd)
-{
- fstring dc_name;
-
- /*
- * Ignore addresses we have already tried.
- */
-
- if (ip_equal(ipzero, *ip))
- return False;
-
- if (!lookup_pdc_name(global_myname, lp_workgroup(), ip, dc_name))
- return False;
-
- return connect_to_domain_password_server(pcli, dc_name, trust_passwd);
-}
-
-/***********************************************************************
- We have been asked to dynamcially determine the IP addresses of
- the PDC and BDC's for this DOMAIN, and query them in turn.
-************************************************************************/
-static BOOL find_connect_pdc(struct cli_state *pcli,
- unsigned char *trust_passwd,
- time_t last_change_time)
-{
- struct in_addr *ip_list = NULL;
- int count = 0;
- int i;
- BOOL connected_ok = False;
- time_t time_now = time(NULL);
- BOOL use_pdc_only = False;
-
- /*
- * If the time the machine password has changed
- * was less than an hour ago then we need to contact
- * the PDC only, as we cannot be sure domain replication
- * has yet taken place. Bug found by Gerald (way to go
- * Gerald !). JRA.
- */
-
- if (time_now - last_change_time < 3600)
- use_pdc_only = True;
-
- if (!get_dc_list(use_pdc_only, lp_workgroup(), &ip_list, &count))
- return False;
-
- /*
- * Firstly try and contact a PDC/BDC who has the same
- * network address as any of our interfaces.
- */
- for(i = 0; i < count; i++) {
- if(!is_local_net(ip_list[i]))
- continue;
-
- if((connected_ok = attempt_connect_to_dc(pcli, &ip_list[i], trust_passwd)))
- break;
-
- ip_list[i] = ipzero; /* Tried and failed. */
- }
-
- /*
- * Secondly try and contact a random PDC/BDC.
- */
- if(!connected_ok) {
- i = (sys_random() % count);
-
- if (!(connected_ok = attempt_connect_to_dc(pcli, &ip_list[i], trust_passwd)))
- ip_list[i] = ipzero; /* Tried and failed. */
- }
-
- /*
- * Finally go through the IP list in turn, ignoring any addresses
- * we have already tried.
- */
- if(!connected_ok) {
- /*
- * Try and connect to any of the other IP addresses in the PDC/BDC list.
- * Note that from a WINS server the #1 IP address is the PDC.
- */
- for(i = 0; i < count; i++) {
- if((connected_ok = attempt_connect_to_dc(pcli, &ip_list[i], trust_passwd)))
- break;
- }
- }
-
- if(ip_list != NULL)
- free((char *)ip_list);
-
-
- return connected_ok;
-}
-
-/***********************************************************************
- Do the same as security=server, but using NT Domain calls and a session
- key from the machine password. If the server parameter is specified
- use it, otherwise figure out a server from the 'password server' param.
-************************************************************************/
+/****************************************************************************
+ Check for a valid username and password in security=domain mode.
+****************************************************************************/
-uint32 domain_client_validate(const auth_usersupplied_info *user_info,
- auth_serversupplied_info *server_info,
- char *server)
+uint32 check_domain_security(const auth_usersupplied_info *user_info,
+ auth_serversupplied_info *server_info)
{
- unsigned char trust_passwd[16];
- fstring remote_machine;
+ uint32 nt_status = NT_STATUS_LOGON_FAILURE;
char *p, *pserver;
- NET_ID_INFO_CTR ctr;
- NET_USER_INFO_3 info3;
- struct cli_state cli;
- uint32 smb_uid_low;
- BOOL connected_ok = False;
+ unsigned char trust_passwd[16];
time_t last_change_time;
- uint32 nt_status;
-
- /*
- * Check that the requested domain is not our own machine name.
- * If it is, we should never check the PDC here, we use our own local
- * password file.
- */
- if(strequal(user_info->domain.str, global_myname)) {
- DEBUG(3,("domain_client_validate: Requested domain was for this machine.\n"));
+ if(lp_security() != SEC_DOMAIN)
return NT_STATUS_LOGON_FAILURE;
- }
+
+ become_root();
/*
* Get the machine account password for our primary domain
*/
+
if (!secrets_fetch_trust_account_password(lp_workgroup(), trust_passwd, &last_change_time))
{
DEBUG(0, ("domain_client_validate: could not fetch trust account password for domain %s\n", lp_workgroup()));
+ unbecome_root();
return NT_STATUS_LOGON_FAILURE;
}
+ unbecome_root();
+
/* Test if machine password is expired and need to be changed */
if (time(NULL) > last_change_time + lp_machine_password_timeout())
{
@@ -313,102 +63,16 @@ uint32 domain_client_validate(const auth_usersupplied_info *user_info,
}
/*
- * At this point, smb_apasswd points to the lanman response to
- * the challenge in local_challenge, and smb_ntpasswd points to
- * the NT response to the challenge in local_challenge. Ship
- * these over the secure channel to a domain controller and
- * see if they were valid.
- */
-
- ZERO_STRUCT(cli);
-
- /*
* Treat each name in the 'password server =' line as a potential
* PDC/BDC. Contact each in turn and try and authenticate.
*/
- if (server) {
- p = server;
- } else {
- pserver = lp_passwordserver();
- if (! *pserver) pserver = "*";
- p = pserver;
- }
-
- while (!connected_ok &&
- next_token(&p,remote_machine,LIST_SEP,sizeof(remote_machine))) {
- if(strequal(remote_machine, "*")) {
- connected_ok = find_connect_pdc(&cli, trust_passwd, last_change_time);
- } else {
- connected_ok = connect_to_domain_password_server(&cli, remote_machine, trust_passwd);
- }
- }
-
- if (!connected_ok) {
- DEBUG(0,("domain_client_validate: Domain password server not available.\n"));
- cli_shutdown(&cli);
- return NT_STATUS_LOGON_FAILURE;
- }
-
- /* We really don't care what LUID we give the user. */
- generate_random_buffer( (unsigned char *)&smb_uid_low, 4, False);
-
- ZERO_STRUCT(info3);
-
- cli_nt_login_network(&cli, user_info->domain.str, user_info->smb_username.str, smb_uid_low, user_info->chal,
- user_info->lm_resp.buffer, user_info->lm_resp.len,
- user_info->nt_resp.buffer, user_info->lm_resp.len,
- &ctr, &info3);
-
- nt_status = cli_nt_error(&cli);
- if (nt_status != NT_STATUS_NOPROBLEMO) {
- DEBUG(0,("domain_client_validate: unable to validate password for user %s in domain \
-%s to Domain controller %s. Error was %s.\n", user_info->smb_username.str, user_info->domain.str, remote_machine, cli_errstr(&cli)));
- }
-
- /*
- * Here, if we really want it, we have lots of info about the user in info3.
- */
-
-#if 0
- /*
- * We don't actually need to do this - plus it fails currently with
- * NT_STATUS_INVALID_INFO_CLASS - we need to know *exactly* what to
- * send here. JRA.
- */
-
- if (nt_status == NT_STATUS_NOPROBLMO) {
- if(cli_nt_logoff(&cli, &ctr) == False) {
- DEBUG(0,("domain_client_validate: unable to log off user %s in domain \
-%s to Domain controller %s. Error was %s.\n", user, domain, remote_machine, cli_errstr(&cli)));
- nt_status = NT_STATUS_LOGON_FAILURE;
- }
- }
-#endif /* 0 */
-
- /* Note - once the cli stream is shutdown the mem_ctx used
- to allocate the other_sids and gids structures has been deleted - so
- these pointers are no longer valid..... */
-
- cli_nt_session_close(&cli);
- cli_ulogoff(&cli);
- cli_shutdown(&cli);
- return nt_status;
-}
-
-/****************************************************************************
- Check for a valid username and password in security=domain mode.
-****************************************************************************/
-
-uint32 check_domain_security(const auth_usersupplied_info *user_info,
- auth_serversupplied_info *server_info)
-{
- uint32 nt_status = NT_STATUS_LOGON_FAILURE;
-
- if(lp_security() != SEC_DOMAIN)
- return NT_STATUS_LOGON_FAILURE;
+ pserver = lp_passwordserver();
+ if (! *pserver) pserver = "*";
+ p = pserver;
- nt_status = domain_client_validate(user_info, server_info, NULL);
+ nt_status = domain_client_validate(user_info, server_info,
+ p, trust_passwd, last_change_time);
return nt_status;
}
diff --git a/source3/auth/auth_rhosts.c b/source3/auth/auth_rhosts.c
index c1bee6247c..f11f9cf777 100644
--- a/source3/auth/auth_rhosts.c
+++ b/source3/auth/auth_rhosts.c
@@ -163,3 +163,24 @@ BOOL check_hosts_equiv(char *user)
return(False);
}
+
+/****************************************************************************
+ Check for a valid .rhosts/hosts.equiv entry for this user
+****************************************************************************/
+
+uint32 check_rhosts_security(const auth_usersupplied_info *user_info,
+ auth_serversupplied_info *server_info)
+{
+ uint32 nt_status = NT_STATUS_LOGON_FAILURE;
+
+ become_root();
+ if (check_hosts_equiv(user_info->smb_username.str)) {
+ nt_status = NT_STATUS_NOPROBLEMO;
+ }
+ unbecome_root();
+
+ return nt_status;
+}
+
+
+
diff --git a/source3/auth/auth_sam.c b/source3/auth/auth_sam.c
index ce0b03d942..927a262dc6 100644
--- a/source3/auth/auth_sam.c
+++ b/source3/auth/auth_sam.c
@@ -208,7 +208,11 @@ uint32 check_smbpasswd_security(const auth_usersupplied_info *user_info, auth_se
pdb_init_sam(&sampass);
/* get the account information */
+
+ become_root();
ret = pdb_getsampwnam(sampass, user_info->smb_username.str);
+ unbecome_root();
+
if (ret == False)
{
DEBUG(1,("Couldn't find user '%s' in passdb file.\n", user_info->smb_username.str));
@@ -216,11 +220,7 @@ uint32 check_smbpasswd_security(const auth_usersupplied_info *user_info, auth_se
return(NT_STATUS_NO_SUCH_USER);
}
- if ((nt_status = smb_password_ok(sampass, user_info, server_info)) != NT_STATUS_NOPROBLEMO)
- {
- pdb_free_sam(sampass);
- return(nt_status);
- }
+ nt_status = smb_password_ok(sampass, user_info, server_info);
pdb_free_sam(sampass);
return nt_status;
diff --git a/source3/auth/auth_unix.c b/source3/auth/auth_unix.c
new file mode 100644
index 0000000000..89e670747f
--- /dev/null
+++ b/source3/auth/auth_unix.c
@@ -0,0 +1,85 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 2.2
+ Password and authentication handling
+ 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"
+
+extern int DEBUGLEVEL;
+
+/****************************************************************************
+update the encrypted smbpasswd file from the plaintext username and password
+
+this ugly hack needs to die, but not quite yet...
+*****************************************************************************/
+static BOOL update_smbpassword_file(char *user, char *password)
+{
+ SAM_ACCOUNT *sampass = NULL;
+ BOOL ret;
+
+ pdb_init_sam(&sampass);
+
+ become_root();
+ ret = pdb_getsampwnam(sampass, user);
+ unbecome_root();
+
+ if(ret == False) {
+ DEBUG(0,("pdb_getsampwnam returned NULL\n"));
+ pdb_free_sam(sampass);
+ return False;
+ }
+
+ /*
+ * Remove the account disabled flag - we are updating the
+ * users password from a login.
+ */
+ pdb_set_acct_ctrl(sampass, pdb_get_acct_ctrl(sampass) & ~ACB_DISABLED);
+
+ /* Here, the flag is one, because we want to ignore the
+ XXXXXXX'd out password */
+ ret = change_oem_password( sampass, password, True);
+ if (ret == False) {
+ DEBUG(3,("change_oem_password returned False\n"));
+ }
+
+ pdb_free_sam(sampass);
+ return ret;
+}
+
+
+/****************************************************************************
+check if a username/password is OK assuming the password
+in PLAIN TEXT
+****************************************************************************/
+
+uint32 check_unix_security(const auth_usersupplied_info *user_info, auth_serversupplied_info *server_info)
+{
+ uint32 nt_status;
+
+ become_root();
+ nt_status = (pass_check(user_info->smb_username.str, user_info->plaintext_password.str,
+ user_info->plaintext_password.len,
+ lp_update_encrypted() ? update_smbpassword_file : NULL)
+ ? NT_STATUS_NOPROBLEMO : NT_STATUS_LOGON_FAILURE);
+ unbecome_root();
+
+ return nt_status;
+}
+
+
diff --git a/source3/include/auth.h b/source3/include/auth.h
index 2c761f57a1..028f8303da 100644
--- a/source3/include/auth.h
+++ b/source3/include/auth.h
@@ -69,10 +69,10 @@ typedef struct usersupplied_info
uint8 chal[8];
- AUTH_STR requested_domain; /* domain name unicode string */
+ AUTH_STR requested_domain; /* domain name string */
AUTH_STR domain; /* domain name after mapping */
AUTH_STR requested_username;
- AUTH_STR smb_username; /* user name unicode string (after mapping) */
+ AUTH_STR smb_username; /* user name string (after mapping) */
AUTH_STR wksta_name; /* workstation name (netbios calling name) unicode string */
} auth_usersupplied_info;
diff --git a/source3/libsmb/domain_client_validate.c b/source3/libsmb/domain_client_validate.c
new file mode 100644
index 0000000000..de5df84e9b
--- /dev/null
+++ b/source3/libsmb/domain_client_validate.c
@@ -0,0 +1,363 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Authenticate against a remote domain
+ Copyright (C) Andrew Tridgell 1992-1998
+ 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"
+
+extern int DEBUGLEVEL;
+extern struct in_addr ipzero;
+
+extern pstring global_myname;
+
+/***********************************************************************
+ Connect to a remote machine for domain security authentication
+ given a name or IP address.
+ ***********************************************************************/
+
+static BOOL connect_to_domain_password_server(struct cli_state *pcli,
+ char *server, unsigned char *trust_passwd)
+{
+ struct in_addr dest_ip;
+ fstring remote_machine;
+
+ if(cli_initialise(pcli) == NULL) {
+ DEBUG(0,("connect_to_domain_password_server: unable to initialize client connection.\n"));
+ return False;
+ }
+
+ if (is_ipaddress(server)) {
+ struct in_addr to_ip;
+
+ /* we shouldn't have 255.255.255.255 forthe IP address of
+ a password server anyways */
+ if ((to_ip.s_addr=inet_addr(server)) == 0xFFFFFFFF) {
+ DEBUG (0,("connect_to_domain_password_server: inet_addr(%s) returned 0xFFFFFFFF!\n", server));
+ return False;
+ }
+
+ if (!name_status_find(0x20, to_ip, remote_machine)) {
+ DEBUG(0, ("connect_to_domain_password_server: Can't "
+ "resolve name for IP %s\n", server));
+ return False;
+ }
+ } else {
+ fstrcpy(remote_machine, server);
+ }
+
+ standard_sub_basic(remote_machine);
+ strupper(remote_machine);
+
+ if(!resolve_name( remote_machine, &dest_ip, 0x20)) {
+ DEBUG(1,("connect_to_domain_password_server: Can't resolve address for %s\n", remote_machine));
+ cli_shutdown(pcli);
+ return False;
+ }
+
+ if (ismyip(dest_ip)) {
+ DEBUG(1,("connect_to_domain_password_server: Password server loop - not using password server %s\n",
+ remote_machine));
+ cli_shutdown(pcli);
+ return False;
+ }
+
+ if (!cli_connect(pcli, remote_machine, &dest_ip)) {
+ DEBUG(0,("connect_to_domain_password_server: unable to connect to SMB server on \
+machine %s. Error was : %s.\n", remote_machine, cli_errstr(pcli) ));
+ cli_shutdown(pcli);
+ return False;
+ }
+
+ if (!attempt_netbios_session_request(pcli, global_myname, remote_machine, &dest_ip)) {
+ DEBUG(0,("connect_to_password_server: machine %s rejected the NetBIOS \
+session request. Error was : %s.\n", remote_machine, cli_errstr(pcli) ));
+ return False;
+ }
+
+ pcli->protocol = PROTOCOL_NT1;
+
+ if (!cli_negprot(pcli)) {
+ DEBUG(0,("connect_to_domain_password_server: machine %s rejected the negotiate protocol. \
+Error was : %s.\n", remote_machine, cli_errstr(pcli) ));
+ cli_shutdown(pcli);
+ return False;
+ }
+
+ if (pcli->protocol != PROTOCOL_NT1) {
+ DEBUG(0,("connect_to_domain_password_server: machine %s didn't negotiate NT protocol.\n",
+ remote_machine));
+ cli_shutdown(pcli);
+ return False;
+ }
+
+ /*
+ * Do an anonymous session setup.
+ */
+
+ if (!cli_session_setup(pcli, "", "", 0, "", 0, "")) {
+ DEBUG(0,("connect_to_domain_password_server: machine %s rejected the session setup. \
+Error was : %s.\n", remote_machine, cli_errstr(pcli) ));
+ cli_shutdown(pcli);
+ return False;
+ }
+
+ if (!(pcli->sec_mode & 1)) {
+ DEBUG(1,("connect_to_domain_password_server: machine %s isn't in user level security mode\n",
+ remote_machine));
+ cli_shutdown(pcli);
+ return False;
+ }
+
+ if (!cli_send_tconX(pcli, "IPC$", "IPC", "", 1)) {
+ DEBUG(0,("connect_to_domain_password_server: machine %s rejected the tconX on the IPC$ share. \
+Error was : %s.\n", remote_machine, cli_errstr(pcli) ));
+ cli_shutdown(pcli);
+ return False;
+ }
+
+ /*
+ * We now have an anonymous connection to IPC$ on the domain password server.
+ */
+
+ /*
+ * Even if the connect succeeds we need to setup the netlogon
+ * pipe here. We do this as we may just have changed the domain
+ * account password on the PDC and yet we may be talking to
+ * a BDC that doesn't have this replicated yet. In this case
+ * a successful connect to a DC needs to take the netlogon connect
+ * into account also. This patch from "Bjart Kvarme" <bjart.kvarme@usit.uio.no>.
+ */
+
+ if(cli_nt_session_open(pcli, PIPE_NETLOGON) == False) {
+ DEBUG(0,("connect_to_domain_password_server: unable to open the domain client session to \
+machine %s. Error was : %s.\n", remote_machine, cli_errstr(pcli)));
+ cli_nt_session_close(pcli);
+ cli_ulogoff(pcli);
+ cli_shutdown(pcli);
+ return False;
+ }
+
+ if (cli_nt_setup_creds(pcli, trust_passwd) == False) {
+ DEBUG(0,("connect_to_domain_password_server: unable to setup the PDC credentials to machine \
+%s. Error was : %s.\n", remote_machine, cli_errstr(pcli)));
+ cli_nt_session_close(pcli);
+ cli_ulogoff(pcli);
+ cli_shutdown(pcli);
+ return(False);
+ }
+
+ return True;
+}
+
+/***********************************************************************
+ Utility function to attempt a connection to an IP address of a DC.
+************************************************************************/
+
+static BOOL attempt_connect_to_dc(struct cli_state *pcli, struct in_addr *ip,
+ unsigned char *trust_passwd)
+{
+ fstring dc_name;
+
+ /*
+ * Ignore addresses we have already tried.
+ */
+
+ if (ip_equal(ipzero, *ip))
+ return False;
+
+ if (!lookup_pdc_name(global_myname, lp_workgroup(), ip, dc_name))
+ return False;
+
+ return connect_to_domain_password_server(pcli, dc_name, trust_passwd);
+}
+
+/***********************************************************************
+ We have been asked to dynamcially determine the IP addresses of
+ the PDC and BDC's for this DOMAIN, and query them in turn.
+************************************************************************/
+static BOOL find_connect_pdc(struct cli_state *pcli,
+ unsigned char *trust_passwd,
+ time_t last_change_time)
+{
+ struct in_addr *ip_list = NULL;
+ int count = 0;
+ int i;
+ BOOL connected_ok = False;
+ time_t time_now = time(NULL);
+ BOOL use_pdc_only = False;
+
+ /*
+ * If the time the machine password has changed
+ * was less than an hour ago then we need to contact
+ * the PDC only, as we cannot be sure domain replication
+ * has yet taken place. Bug found by Gerald (way to go
+ * Gerald !). JRA.
+ */
+
+ if (time_now - last_change_time < 3600)
+ use_pdc_only = True;
+
+ if (!get_dc_list(use_pdc_only, lp_workgroup(), &ip_list, &count))
+ return False;
+
+ /*
+ * Firstly try and contact a PDC/BDC who has the same
+ * network address as any of our interfaces.
+ */
+ for(i = 0; i < count; i++) {
+ if(!is_local_net(ip_list[i]))
+ continue;
+
+ if((connected_ok = attempt_connect_to_dc(pcli, &ip_list[i], trust_passwd)))
+ break;
+
+ ip_list[i] = ipzero; /* Tried and failed. */
+ }
+
+ /*
+ * Secondly try and contact a random PDC/BDC.
+ */
+ if(!connected_ok) {
+ i = (sys_random() % count);
+
+ if (!(connected_ok = attempt_connect_to_dc(pcli, &ip_list[i], trust_passwd)))
+ ip_list[i] = ipzero; /* Tried and failed. */
+ }
+
+ /*
+ * Finally go through the IP list in turn, ignoring any addresses
+ * we have already tried.
+ */
+ if(!connected_ok) {
+ /*
+ * Try and connect to any of the other IP addresses in the PDC/BDC list.
+ * Note that from a WINS server the #1 IP address is the PDC.
+ */
+ for(i = 0; i < count; i++) {
+ if((connected_ok = attempt_connect_to_dc(pcli, &ip_list[i], trust_passwd)))
+ break;
+ }
+ }
+
+ if(ip_list != NULL)
+ free((char *)ip_list);
+
+
+ return connected_ok;
+}
+
+/***********************************************************************
+ Do the same as security=server, but using NT Domain calls and a session
+ key from the machine password. If the server parameter is specified
+ use it, otherwise figure out a server from the 'password server' param.
+************************************************************************/
+
+uint32 domain_client_validate(const auth_usersupplied_info *user_info,
+ auth_serversupplied_info *server_info,
+ char *server, unsigned char *trust_passwd,
+ time_t last_change_time)
+{
+ fstring remote_machine;
+ NET_ID_INFO_CTR ctr;
+ NET_USER_INFO_3 info3;
+ struct cli_state cli;
+ uint32 smb_uid_low;
+ BOOL connected_ok = False;
+ uint32 nt_status;
+
+ /*
+ * Check that the requested domain is not our own machine name.
+ * If it is, we should never check the PDC here, we use our own local
+ * password file.
+ */
+
+ if(strequal(user_info->domain.str, global_myname)) {
+ DEBUG(3,("domain_client_validate: Requested domain was for this machine.\n"));
+ return NT_STATUS_LOGON_FAILURE;
+ }
+
+ /*
+ * At this point, smb_apasswd points to the lanman response to
+ * the challenge in local_challenge, and smb_ntpasswd points to
+ * the NT response to the challenge in local_challenge. Ship
+ * these over the secure channel to a domain controller and
+ * see if they were valid.
+ */
+
+ ZERO_STRUCT(cli);
+
+ while (!connected_ok &&
+ next_token(&server,remote_machine,LIST_SEP,sizeof(remote_machine))) {
+ if(strequal(remote_machine, "*")) {
+ connected_ok = find_connect_pdc(&cli, trust_passwd, last_change_time);
+ } else {
+ connected_ok = connect_to_domain_password_server(&cli, remote_machine, trust_passwd);
+ }
+ }
+
+ if (!connected_ok) {
+ DEBUG(0,("domain_client_validate: Domain password server not available.\n"));
+ cli_shutdown(&cli);
+ return NT_STATUS_LOGON_FAILURE;
+ }
+
+ /* We really don't care what LUID we give the user. */
+ generate_random_buffer( (unsigned char *)&smb_uid_low, 4, False);
+
+ ZERO_STRUCT(info3);
+
+ if (!cli_nt_login_network(&cli, user_info, smb_uid_low, &ctr, &info3)) {
+ nt_status = cli_nt_error(&cli);
+ DEBUG(0,("domain_client_validate: unable to validate password for user %s in domain \
+%s to Domain controller %s. Error was %s.\n", user_info->smb_username.str, user_info->domain.str, remote_machine, cli_errstr(&cli)));
+ } else {
+ nt_status = NT_STATUS_NOPROBLEMO;
+ }
+
+ /*
+ * Here, if we really want it, we have lots of info about the user in info3.
+ */
+
+#if 0
+ /*
+ * We don't actually need to do this - plus it fails currently with
+ * NT_STATUS_INVALID_INFO_CLASS - we need to know *exactly* what to
+ * send here. JRA.
+ */
+
+ if (nt_status == NT_STATUS_NOPROBLMO) {
+ if(cli_nt_logoff(&cli, &ctr) == False) {
+ DEBUG(0,("domain_client_validate: unable to log off user %s in domain \
+%s to Domain controller %s. Error was %s.\n", user, domain, remote_machine, cli_errstr(&cli)));
+ nt_status = NT_STATUS_LOGON_FAILURE;
+ }
+ }
+#endif /* 0 */
+
+ /* Note - once the cli stream is shutdown the mem_ctx used
+ to allocate the other_sids and gids structures has been deleted - so
+ these pointers are no longer valid..... */
+
+ cli_nt_session_close(&cli);
+ cli_ulogoff(&cli);
+ cli_shutdown(&cli);
+ return nt_status;
+}
+
diff --git a/source3/nsswitch/winbindd_pam.c b/source3/nsswitch/winbindd_pam.c
index 558f418d94..4dc08c6086 100644
--- a/source3/nsswitch/winbindd_pam.c
+++ b/source3/nsswitch/winbindd_pam.c
@@ -55,6 +55,8 @@ enum winbindd_result winbindd_pam_auth(struct winbindd_cli_state *state)
BOOL result;
fstring name_domain, name_user;
int passlen;
+ unsigned char trust_passwd[16];
+ time_t last_change_time;
unsigned char local_lm_response[24];
unsigned char local_nt_response[24];
@@ -113,12 +115,23 @@ enum winbindd_result winbindd_pam_auth(struct winbindd_cli_state *state)
return WINBINDD_ERROR;
}
+ /*
+ * Get the machine account password for our primary domain
+ */
+
+ if (!secrets_fetch_trust_account_password(lp_workgroup(), trust_passwd, &last_change_time))
+ {
+ DEBUG(0, ("winbindd_pam_auth: could not fetch trust account password for domain %s\n", lp_workgroup()));
+ return WINBINDD_ERROR;
+ }
+
/* So domain_client_validate() actually opens a new connection
for each authentication performed. This can theoretically
be optimised to use an already open IPC$ connection. */
result = (domain_client_validate(&user_info, &server_info,
- server_state.controller) == NT_STATUS_NOPROBLEMO);
+ server_state.controller, trust_passwd,
+ last_change_time) == NT_STATUS_NOPROBLEMO);
return result ? WINBINDD_OK : WINBINDD_ERROR;
}
diff --git a/source3/rpc_client/cli_login.c b/source3/rpc_client/cli_login.c
index a099936476..7e2090164c 100644
--- a/source3/rpc_client/cli_login.c
+++ b/source3/rpc_client/cli_login.c
@@ -155,22 +155,20 @@ NT login - network.
password equivalents over the network. JRA.
****************************************************************************/
-BOOL cli_nt_login_network(struct cli_state *cli, const char *domain, const char *username,
- uint32 smb_userid_low, const uchar lm_chal[8],
- const uchar *lm_chal_resp, int lm_chal_resp_len,
- const uchar *nt_chal_resp, int nt_chal_resp_len,
- NET_ID_INFO_CTR *ctr, NET_USER_INFO_3 *user_info3)
+BOOL cli_nt_login_network(struct cli_state *cli, const auth_usersupplied_info *user_info,
+ uint32 smb_userid_low, NET_ID_INFO_CTR *ctr,
+ NET_USER_INFO_3 *user_info3)
{
DEBUG(5,("cli_nt_login_network: %d\n", __LINE__));
/* indicate a "network" login */
ctr->switch_value = NET_LOGON_TYPE;
/* Create the structure needed for SAM logon. */
- init_id_info2(&ctr->auth.id2, domain, 0, smb_userid_low, 0,
- username, cli->clnt_name_slash,
- lm_chal,
- lm_chal_resp, lm_chal_resp_len,
- nt_chal_resp, nt_chal_resp_len);
+ init_id_info2(&ctr->auth.id2, user_info->domain.str, 0, smb_userid_low, 0,
+ user_info->smb_username.str, cli->clnt_name_slash,
+ user_info->chal,
+ user_info->lm_resp.buffer, user_info->lm_resp.len,
+ user_info->nt_resp.buffer, user_info->nt_resp.len);
/* Send client sam-logon request - update credentials on success. */
return cli_net_sam_logon(cli, ctr, user_info3);
diff --git a/source3/rpc_server/srv_netlog_nt.c b/source3/rpc_server/srv_netlog_nt.c
index b7e1d3538d..5cf8f6732e 100644
--- a/source3/rpc_server/srv_netlog_nt.c
+++ b/source3/rpc_server/srv_netlog_nt.c
@@ -446,7 +446,6 @@ uint32 _net_sam_logoff(pipes_struct *p, NET_Q_SAM_LOGOFF *q_u, NET_R_SAM_LOGOFF
static uint32 _net_logon_any(NET_ID_INFO_CTR *ctr, char *user, char *domain, char *sess_key)
{
-
uint32 nt_status = NT_STATUS_LOGON_FAILURE;
unsigned char local_lm_response[24];
@@ -490,6 +489,8 @@ static uint32 _net_logon_any(NET_ID_INFO_CTR *ctr, char *user, char *domain, cha
DEBUG(10,("_net_logon_any: Attempting validation level %d.\n", ctr->switch_value));
switch (ctr->switch_value) {
case NET_LOGON_TYPE:
+ /* Standard challange/response authenticaion */
+
user_info.lm_resp.buffer = (uint8 *)ctr->auth.id2.lm_chal_resp.buffer;
user_info.lm_resp.len = ctr->auth.id2.lm_chal_resp.str_str_len;
user_info.nt_resp.buffer = (uint8 *)ctr->auth.id2.nt_chal_resp.buffer;
@@ -497,6 +498,9 @@ static uint32 _net_logon_any(NET_ID_INFO_CTR *ctr, char *user, char *domain, cha
memcpy(user_info.chal, ctr->auth.id2.lm_chal, 8);
break;
case INTERACTIVE_LOGON_TYPE:
+ /* 'Interactive' autheticaion, supplies the password in its MD4 form, encrypted
+ with the session key. We will convert this to challange/responce for the
+ auth subsystem to chew on */
{
char nt_pwd[16];
char lm_pwd[16];
@@ -539,25 +543,6 @@ static uint32 _net_logon_any(NET_ID_INFO_CTR *ctr, char *user, char *domain, cha
user_info.nt_resp.len = 24;
break;
}
-#if 0
- case GENERAL_LOGON_TYPE:
- /* plaintext login. plaintext username and password */
-
- /*
- * Not encrypted - do so.
- */
-
- SMBencrypt( (uchar *)ctr->auth.id4....., user_info.chal, local_lm_response);
- SMBNTencrypt((uchar *)ctr->auth.id4......., user_info.chal, local_nt_response);
- user_info.lm_resp.buffer = (uint8 *)local_lm_response;
- user_info.lm_resp.len = 24;
- user_info.nt_resp.buffer = (uint8 *)local_nt_response;
- user_info.nt_resp.len = 24;
-
- user_info.plaintext_password.str = ;
- user_info.plaintext_password.len = ;
- break;
-#endif
default:
DEBUG(2,("SAM Logon: unsupported switch value\n"));
return NT_STATUS_INVALID_INFO_CLASS;
diff --git a/source3/smbd/auth.c b/source3/smbd/auth.c
index 94008e4d00..bbcf34e8ca 100644
--- a/source3/smbd/auth.c
+++ b/source3/smbd/auth.c
@@ -27,46 +27,6 @@ extern int DEBUGLEVEL;
extern pstring global_myname;
-
-/****************************************************************************
-update the encrypted smbpasswd file from the plaintext username and password
-
-this ugly hack needs to die, but not quite yet...
-*****************************************************************************/
-static BOOL update_smbpassword_file(char *user, char *password)
-{
- SAM_ACCOUNT *sampass = NULL;
- BOOL ret;
-
- pdb_init_sam(&sampass);
-
- become_root();
- ret = pdb_getsampwnam(sampass, user);
- unbecome_root();
-
- if(ret == False) {
- DEBUG(0,("update_smbpassword_file: pdb_getsampwnam failed to locate %s\n", user));
- pdb_free_sam(sampass);
- return False;
- }
-
- /*
- * Remove the account disabled flag - we are updating the
- * users password from a login.
- */
- pdb_set_acct_ctrl(sampass, pdb_get_acct_ctrl(sampass) & ~ACB_DISABLED);
-
- /* Here, the flag is one, because we want to ignore the
- XXXXXXX'd out password */
- ret = change_oem_password( sampass, password, True);
- if (ret == False) {
- DEBUG(3,("change_oem_password returned False\n"));
- }
-
- pdb_free_sam(sampass);
- return ret;
-}
-
/****************************************************************************
Check user is in correct domain if required
****************************************************************************/
@@ -88,21 +48,29 @@ static BOOL check_domain_match(char *user, char *domain)
}
}
+/****************************************************************************
+ Check a users password, as given in the user-info struct and return various
+ interesting details in the server_info struct.
+
+ This functions does NOT need to be in a become_root()/unbecome_root() pair
+ as it makes the calls itself when needed.
+****************************************************************************/
uint32 check_password(const auth_usersupplied_info *user_info, auth_serversupplied_info *server_info)
{
uint32 nt_status = NT_STATUS_LOGON_FAILURE;
-
+ BOOL done_pam = False;
+
DEBUG(3, ("check_password: Checking password for user %s with the new password interface\n", user_info->smb_username.str));
- if (check_hosts_equiv(user_info->smb_username.str)) {
- nt_status = NT_STATUS_NOPROBLEMO;
- }
-
if (!check_domain_match(user_info->smb_username.str, user_info->domain.str)) {
return NT_STATUS_LOGON_FAILURE;
}
+ if (nt_status != NT_STATUS_NOPROBLEMO) {
+ nt_status = check_rhosts_security(user_info, server_info);
+ }
+
if ((lp_security() == SEC_DOMAIN) && (nt_status != NT_STATUS_NOPROBLEMO)) {
nt_status = check_domain_security(user_info, server_info);
}
@@ -115,28 +83,23 @@ uint32 check_password(const auth_usersupplied_info *user_info, auth_serversuppli
smb_user_control(user_info->smb_username.str, nt_status);
}
- if ((nt_status != NT_STATUS_NOPROBLEMO)
- && (user_info->plaintext_password.len > 0)
- && (!lp_plaintext_to_smbpasswd())) {
- return (pass_check(user_info->smb_username.str,
- user_info->plaintext_password.str,
- user_info->plaintext_password.len,
- lp_update_encrypted() ?
- update_smbpassword_file : NULL)
- ? NT_STATUS_NOPROBLEMO : NT_STATUS_LOGON_FAILURE);
- }
-
if (nt_status != NT_STATUS_NOPROBLEMO) {
- nt_status = check_smbpasswd_security(user_info, server_info);
+ if ((user_info->plaintext_password.len > 0)
+ && (!lp_plaintext_to_smbpasswd())) {
+ nt_status = check_unix_security(user_info, server_info);
+ done_pam = True;
+ } else {
+ nt_status = check_smbpasswd_security(user_info, server_info);
+ }
}
-
- if (nt_status == NT_STATUS_NOPROBLEMO) {
+
+ if ((nt_status == NT_STATUS_NOPROBLEMO) && !done_pam) {
/* We might not be root if we are an RPC call */
become_root();
nt_status = smb_pam_accountcheck(user_info->smb_username.str);
unbecome_root();
}
-
+
if (nt_status == NT_STATUS_NOPROBLEMO) {
DEBUG(5, ("check_password: Password for user %s suceeded\n", user_info->smb_username.str));
} else {
diff --git a/source3/smbd/auth_domain.c b/source3/smbd/auth_domain.c
index e94ea13edc..a2e3c7a9b5 100644
--- a/source3/smbd/auth_domain.c
+++ b/source3/smbd/auth_domain.c
@@ -23,289 +23,39 @@
#include "includes.h"
extern int DEBUGLEVEL;
-extern struct in_addr ipzero;
BOOL global_machine_password_needs_changing = False;
-extern pstring global_myname;
-
-/***********************************************************************
- Connect to a remote machine for domain security authentication
- given a name or IP address.
- ***********************************************************************/
-
-static BOOL connect_to_domain_password_server(struct cli_state *pcli,
- char *server, unsigned char *trust_passwd)
-{
- struct in_addr dest_ip;
- fstring remote_machine;
-
- if(cli_initialise(pcli) == NULL) {
- DEBUG(0,("connect_to_domain_password_server: unable to initialize client connection.\n"));
- return False;
- }
-
- if (is_ipaddress(server)) {
- struct in_addr to_ip;
-
- /* we shouldn't have 255.255.255.255 forthe IP address of
- a password server anyways */
- if ((to_ip.s_addr=inet_addr(server)) == 0xFFFFFFFF) {
- DEBUG (0,("connect_to_domain_password_server: inet_addr(%s) returned 0xFFFFFFFF!\n", server));
- return False;
- }
-
- if (!name_status_find(0x20, to_ip, remote_machine)) {
- DEBUG(0, ("connect_to_domain_password_server: Can't "
- "resolve name for IP %s\n", server));
- return False;
- }
- } else {
- fstrcpy(remote_machine, server);
- }
-
- standard_sub_basic(remote_machine);
- strupper(remote_machine);
-
- if(!resolve_name( remote_machine, &dest_ip, 0x20)) {
- DEBUG(1,("connect_to_domain_password_server: Can't resolve address for %s\n", remote_machine));
- cli_shutdown(pcli);
- return False;
- }
-
- if (ismyip(dest_ip)) {
- DEBUG(1,("connect_to_domain_password_server: Password server loop - not using password server %s\n",
- remote_machine));
- cli_shutdown(pcli);
- return False;
- }
-
- if (!cli_connect(pcli, remote_machine, &dest_ip)) {
- DEBUG(0,("connect_to_domain_password_server: unable to connect to SMB server on \
-machine %s. Error was : %s.\n", remote_machine, cli_errstr(pcli) ));
- cli_shutdown(pcli);
- return False;
- }
-
- if (!attempt_netbios_session_request(pcli, global_myname, remote_machine, &dest_ip)) {
- DEBUG(0,("connect_to_password_server: machine %s rejected the NetBIOS \
-session request. Error was : %s.\n", remote_machine, cli_errstr(pcli) ));
- return False;
- }
-
- pcli->protocol = PROTOCOL_NT1;
-
- if (!cli_negprot(pcli)) {
- DEBUG(0,("connect_to_domain_password_server: machine %s rejected the negotiate protocol. \
-Error was : %s.\n", remote_machine, cli_errstr(pcli) ));
- cli_shutdown(pcli);
- return False;
- }
-
- if (pcli->protocol != PROTOCOL_NT1) {
- DEBUG(0,("connect_to_domain_password_server: machine %s didn't negotiate NT protocol.\n",
- remote_machine));
- cli_shutdown(pcli);
- return False;
- }
-
- /*
- * Do an anonymous session setup.
- */
-
- if (!cli_session_setup(pcli, "", "", 0, "", 0, "")) {
- DEBUG(0,("connect_to_domain_password_server: machine %s rejected the session setup. \
-Error was : %s.\n", remote_machine, cli_errstr(pcli) ));
- cli_shutdown(pcli);
- return False;
- }
-
- if (!(pcli->sec_mode & 1)) {
- DEBUG(1,("connect_to_domain_password_server: machine %s isn't in user level security mode\n",
- remote_machine));
- cli_shutdown(pcli);
- return False;
- }
-
- if (!cli_send_tconX(pcli, "IPC$", "IPC", "", 1)) {
- DEBUG(0,("connect_to_domain_password_server: machine %s rejected the tconX on the IPC$ share. \
-Error was : %s.\n", remote_machine, cli_errstr(pcli) ));
- cli_shutdown(pcli);
- return False;
- }
-
- /*
- * We now have an anonymous connection to IPC$ on the domain password server.
- */
-
- /*
- * Even if the connect succeeds we need to setup the netlogon
- * pipe here. We do this as we may just have changed the domain
- * account password on the PDC and yet we may be talking to
- * a BDC that doesn't have this replicated yet. In this case
- * a successful connect to a DC needs to take the netlogon connect
- * into account also. This patch from "Bjart Kvarme" <bjart.kvarme@usit.uio.no>.
- */
-
- if(cli_nt_session_open(pcli, PIPE_NETLOGON) == False) {
- DEBUG(0,("connect_to_domain_password_server: unable to open the domain client session to \
-machine %s. Error was : %s.\n", remote_machine, cli_errstr(pcli)));
- cli_nt_session_close(pcli);
- cli_ulogoff(pcli);
- cli_shutdown(pcli);
- return False;
- }
-
- if (cli_nt_setup_creds(pcli, trust_passwd) == False) {
- DEBUG(0,("connect_to_domain_password_server: unable to setup the PDC credentials to machine \
-%s. Error was : %s.\n", remote_machine, cli_errstr(pcli)));
- cli_nt_session_close(pcli);
- cli_ulogoff(pcli);
- cli_shutdown(pcli);
- return(False);
- }
-
- return True;
-}
-
-/***********************************************************************
- Utility function to attempt a connection to an IP address of a DC.
-************************************************************************/
-
-static BOOL attempt_connect_to_dc(struct cli_state *pcli, struct in_addr *ip,
- unsigned char *trust_passwd)
-{
- fstring dc_name;
-
- /*
- * Ignore addresses we have already tried.
- */
-
- if (ip_equal(ipzero, *ip))
- return False;
-
- if (!lookup_pdc_name(global_myname, lp_workgroup(), ip, dc_name))
- return False;
-
- return connect_to_domain_password_server(pcli, dc_name, trust_passwd);
-}
-
-/***********************************************************************
- We have been asked to dynamcially determine the IP addresses of
- the PDC and BDC's for this DOMAIN, and query them in turn.
-************************************************************************/
-static BOOL find_connect_pdc(struct cli_state *pcli,
- unsigned char *trust_passwd,
- time_t last_change_time)
-{
- struct in_addr *ip_list = NULL;
- int count = 0;
- int i;
- BOOL connected_ok = False;
- time_t time_now = time(NULL);
- BOOL use_pdc_only = False;
-
- /*
- * If the time the machine password has changed
- * was less than an hour ago then we need to contact
- * the PDC only, as we cannot be sure domain replication
- * has yet taken place. Bug found by Gerald (way to go
- * Gerald !). JRA.
- */
-
- if (time_now - last_change_time < 3600)
- use_pdc_only = True;
-
- if (!get_dc_list(use_pdc_only, lp_workgroup(), &ip_list, &count))
- return False;
-
- /*
- * Firstly try and contact a PDC/BDC who has the same
- * network address as any of our interfaces.
- */
- for(i = 0; i < count; i++) {
- if(!is_local_net(ip_list[i]))
- continue;
-
- if((connected_ok = attempt_connect_to_dc(pcli, &ip_list[i], trust_passwd)))
- break;
-
- ip_list[i] = ipzero; /* Tried and failed. */
- }
-
- /*
- * Secondly try and contact a random PDC/BDC.
- */
- if(!connected_ok) {
- i = (sys_random() % count);
-
- if (!(connected_ok = attempt_connect_to_dc(pcli, &ip_list[i], trust_passwd)))
- ip_list[i] = ipzero; /* Tried and failed. */
- }
-
- /*
- * Finally go through the IP list in turn, ignoring any addresses
- * we have already tried.
- */
- if(!connected_ok) {
- /*
- * Try and connect to any of the other IP addresses in the PDC/BDC list.
- * Note that from a WINS server the #1 IP address is the PDC.
- */
- for(i = 0; i < count; i++) {
- if((connected_ok = attempt_connect_to_dc(pcli, &ip_list[i], trust_passwd)))
- break;
- }
- }
-
- if(ip_list != NULL)
- free((char *)ip_list);
-
-
- return connected_ok;
-}
-
-/***********************************************************************
- Do the same as security=server, but using NT Domain calls and a session
- key from the machine password. If the server parameter is specified
- use it, otherwise figure out a server from the 'password server' param.
-************************************************************************/
+/****************************************************************************
+ Check for a valid username and password in security=domain mode.
+****************************************************************************/
-uint32 domain_client_validate(const auth_usersupplied_info *user_info,
- auth_serversupplied_info *server_info,
- char *server)
+uint32 check_domain_security(const auth_usersupplied_info *user_info,
+ auth_serversupplied_info *server_info)
{
- unsigned char trust_passwd[16];
- fstring remote_machine;
+ uint32 nt_status = NT_STATUS_LOGON_FAILURE;
char *p, *pserver;
- NET_ID_INFO_CTR ctr;
- NET_USER_INFO_3 info3;
- struct cli_state cli;
- uint32 smb_uid_low;
- BOOL connected_ok = False;
+ unsigned char trust_passwd[16];
time_t last_change_time;
- uint32 nt_status;
-
- /*
- * Check that the requested domain is not our own machine name.
- * If it is, we should never check the PDC here, we use our own local
- * password file.
- */
- if(strequal(user_info->domain.str, global_myname)) {
- DEBUG(3,("domain_client_validate: Requested domain was for this machine.\n"));
+ if(lp_security() != SEC_DOMAIN)
return NT_STATUS_LOGON_FAILURE;
- }
+
+ become_root();
/*
* Get the machine account password for our primary domain
*/
+
if (!secrets_fetch_trust_account_password(lp_workgroup(), trust_passwd, &last_change_time))
{
DEBUG(0, ("domain_client_validate: could not fetch trust account password for domain %s\n", lp_workgroup()));
+ unbecome_root();
return NT_STATUS_LOGON_FAILURE;
}
+ unbecome_root();
+
/* Test if machine password is expired and need to be changed */
if (time(NULL) > last_change_time + lp_machine_password_timeout())
{
@@ -313,102 +63,16 @@ uint32 domain_client_validate(const auth_usersupplied_info *user_info,
}
/*
- * At this point, smb_apasswd points to the lanman response to
- * the challenge in local_challenge, and smb_ntpasswd points to
- * the NT response to the challenge in local_challenge. Ship
- * these over the secure channel to a domain controller and
- * see if they were valid.
- */
-
- ZERO_STRUCT(cli);
-
- /*
* Treat each name in the 'password server =' line as a potential
* PDC/BDC. Contact each in turn and try and authenticate.
*/
- if (server) {
- p = server;
- } else {
- pserver = lp_passwordserver();
- if (! *pserver) pserver = "*";
- p = pserver;
- }
-
- while (!connected_ok &&
- next_token(&p,remote_machine,LIST_SEP,sizeof(remote_machine))) {
- if(strequal(remote_machine, "*")) {
- connected_ok = find_connect_pdc(&cli, trust_passwd, last_change_time);
- } else {
- connected_ok = connect_to_domain_password_server(&cli, remote_machine, trust_passwd);
- }
- }
-
- if (!connected_ok) {
- DEBUG(0,("domain_client_validate: Domain password server not available.\n"));
- cli_shutdown(&cli);
- return NT_STATUS_LOGON_FAILURE;
- }
-
- /* We really don't care what LUID we give the user. */
- generate_random_buffer( (unsigned char *)&smb_uid_low, 4, False);
-
- ZERO_STRUCT(info3);
-
- cli_nt_login_network(&cli, user_info->domain.str, user_info->smb_username.str, smb_uid_low, user_info->chal,
- user_info->lm_resp.buffer, user_info->lm_resp.len,
- user_info->nt_resp.buffer, user_info->lm_resp.len,
- &ctr, &info3);
-
- nt_status = cli_nt_error(&cli);
- if (nt_status != NT_STATUS_NOPROBLEMO) {
- DEBUG(0,("domain_client_validate: unable to validate password for user %s in domain \
-%s to Domain controller %s. Error was %s.\n", user_info->smb_username.str, user_info->domain.str, remote_machine, cli_errstr(&cli)));
- }
-
- /*
- * Here, if we really want it, we have lots of info about the user in info3.
- */
-
-#if 0
- /*
- * We don't actually need to do this - plus it fails currently with
- * NT_STATUS_INVALID_INFO_CLASS - we need to know *exactly* what to
- * send here. JRA.
- */
-
- if (nt_status == NT_STATUS_NOPROBLMO) {
- if(cli_nt_logoff(&cli, &ctr) == False) {
- DEBUG(0,("domain_client_validate: unable to log off user %s in domain \
-%s to Domain controller %s. Error was %s.\n", user, domain, remote_machine, cli_errstr(&cli)));
- nt_status = NT_STATUS_LOGON_FAILURE;
- }
- }
-#endif /* 0 */
-
- /* Note - once the cli stream is shutdown the mem_ctx used
- to allocate the other_sids and gids structures has been deleted - so
- these pointers are no longer valid..... */
-
- cli_nt_session_close(&cli);
- cli_ulogoff(&cli);
- cli_shutdown(&cli);
- return nt_status;
-}
-
-/****************************************************************************
- Check for a valid username and password in security=domain mode.
-****************************************************************************/
-
-uint32 check_domain_security(const auth_usersupplied_info *user_info,
- auth_serversupplied_info *server_info)
-{
- uint32 nt_status = NT_STATUS_LOGON_FAILURE;
-
- if(lp_security() != SEC_DOMAIN)
- return NT_STATUS_LOGON_FAILURE;
+ pserver = lp_passwordserver();
+ if (! *pserver) pserver = "*";
+ p = pserver;
- nt_status = domain_client_validate(user_info, server_info, NULL);
+ nt_status = domain_client_validate(user_info, server_info,
+ p, trust_passwd, last_change_time);
return nt_status;
}
diff --git a/source3/smbd/auth_rhosts.c b/source3/smbd/auth_rhosts.c
index c1bee6247c..f11f9cf777 100644
--- a/source3/smbd/auth_rhosts.c
+++ b/source3/smbd/auth_rhosts.c
@@ -163,3 +163,24 @@ BOOL check_hosts_equiv(char *user)
return(False);
}
+
+/****************************************************************************
+ Check for a valid .rhosts/hosts.equiv entry for this user
+****************************************************************************/
+
+uint32 check_rhosts_security(const auth_usersupplied_info *user_info,
+ auth_serversupplied_info *server_info)
+{
+ uint32 nt_status = NT_STATUS_LOGON_FAILURE;
+
+ become_root();
+ if (check_hosts_equiv(user_info->smb_username.str)) {
+ nt_status = NT_STATUS_NOPROBLEMO;
+ }
+ unbecome_root();
+
+ return nt_status;
+}
+
+
+
diff --git a/source3/smbd/auth_smbpasswd.c b/source3/smbd/auth_smbpasswd.c
index ce0b03d942..927a262dc6 100644
--- a/source3/smbd/auth_smbpasswd.c
+++ b/source3/smbd/auth_smbpasswd.c
@@ -208,7 +208,11 @@ uint32 check_smbpasswd_security(const auth_usersupplied_info *user_info, auth_se
pdb_init_sam(&sampass);
/* get the account information */
+
+ become_root();
ret = pdb_getsampwnam(sampass, user_info->smb_username.str);
+ unbecome_root();
+
if (ret == False)
{
DEBUG(1,("Couldn't find user '%s' in passdb file.\n", user_info->smb_username.str));
@@ -216,11 +220,7 @@ uint32 check_smbpasswd_security(const auth_usersupplied_info *user_info, auth_se
return(NT_STATUS_NO_SUCH_USER);
}
- if ((nt_status = smb_password_ok(sampass, user_info, server_info)) != NT_STATUS_NOPROBLEMO)
- {
- pdb_free_sam(sampass);
- return(nt_status);
- }
+ nt_status = smb_password_ok(sampass, user_info, server_info);
pdb_free_sam(sampass);
return nt_status;
diff --git a/source3/smbd/auth_unix.c b/source3/smbd/auth_unix.c
new file mode 100644
index 0000000000..89e670747f
--- /dev/null
+++ b/source3/smbd/auth_unix.c
@@ -0,0 +1,85 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 2.2
+ Password and authentication handling
+ 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"
+
+extern int DEBUGLEVEL;
+
+/****************************************************************************
+update the encrypted smbpasswd file from the plaintext username and password
+
+this ugly hack needs to die, but not quite yet...
+*****************************************************************************/
+static BOOL update_smbpassword_file(char *user, char *password)
+{
+ SAM_ACCOUNT *sampass = NULL;
+ BOOL ret;
+
+ pdb_init_sam(&sampass);
+
+ become_root();
+ ret = pdb_getsampwnam(sampass, user);
+ unbecome_root();
+
+ if(ret == False) {
+ DEBUG(0,("pdb_getsampwnam returned NULL\n"));
+ pdb_free_sam(sampass);
+ return False;
+ }
+
+ /*
+ * Remove the account disabled flag - we are updating the
+ * users password from a login.
+ */
+ pdb_set_acct_ctrl(sampass, pdb_get_acct_ctrl(sampass) & ~ACB_DISABLED);
+
+ /* Here, the flag is one, because we want to ignore the
+ XXXXXXX'd out password */
+ ret = change_oem_password( sampass, password, True);
+ if (ret == False) {
+ DEBUG(3,("change_oem_password returned False\n"));
+ }
+
+ pdb_free_sam(sampass);
+ return ret;
+}
+
+
+/****************************************************************************
+check if a username/password is OK assuming the password
+in PLAIN TEXT
+****************************************************************************/
+
+uint32 check_unix_security(const auth_usersupplied_info *user_info, auth_serversupplied_info *server_info)
+{
+ uint32 nt_status;
+
+ become_root();
+ nt_status = (pass_check(user_info->smb_username.str, user_info->plaintext_password.str,
+ user_info->plaintext_password.len,
+ lp_update_encrypted() ? update_smbpassword_file : NULL)
+ ? NT_STATUS_NOPROBLEMO : NT_STATUS_LOGON_FAILURE);
+ unbecome_root();
+
+ return nt_status;
+}
+
+