diff options
-rw-r--r-- | source3/Makefile.in | 7 | ||||
-rw-r--r-- | source3/auth/auth.c | 83 | ||||
-rw-r--r-- | source3/auth/auth_domain.c | 374 | ||||
-rw-r--r-- | source3/auth/auth_rhosts.c | 21 | ||||
-rw-r--r-- | source3/auth/auth_sam.c | 10 | ||||
-rw-r--r-- | source3/auth/auth_unix.c | 85 | ||||
-rw-r--r-- | source3/include/auth.h | 4 | ||||
-rw-r--r-- | source3/libsmb/domain_client_validate.c | 363 | ||||
-rw-r--r-- | source3/nsswitch/winbindd_pam.c | 15 | ||||
-rw-r--r-- | source3/rpc_client/cli_login.c | 18 | ||||
-rw-r--r-- | source3/rpc_server/srv_netlog_nt.c | 25 | ||||
-rw-r--r-- | source3/smbd/auth.c | 83 | ||||
-rw-r--r-- | source3/smbd/auth_domain.c | 374 | ||||
-rw-r--r-- | source3/smbd/auth_rhosts.c | 21 | ||||
-rw-r--r-- | source3/smbd/auth_smbpasswd.c | 10 | ||||
-rw-r--r-- | source3/smbd/auth_unix.c | 85 |
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; +} + + |