diff options
Diffstat (limited to 'source3/smbd')
-rw-r--r-- | source3/smbd/auth.c | 275 | ||||
-rw-r--r-- | source3/smbd/auth_domain.c | 417 | ||||
-rw-r--r-- | source3/smbd/auth_rhosts.c | 165 | ||||
-rw-r--r-- | source3/smbd/auth_server.c | 244 | ||||
-rw-r--r-- | source3/smbd/auth_smbpasswd.c | 229 | ||||
-rw-r--r-- | source3/smbd/auth_util.c | 141 | ||||
-rw-r--r-- | source3/smbd/negprot.c | 3 | ||||
-rw-r--r-- | source3/smbd/password.c | 1072 | ||||
-rw-r--r-- | source3/smbd/reply.c | 256 |
9 files changed, 1520 insertions, 1282 deletions
diff --git a/source3/smbd/auth.c b/source3/smbd/auth.c new file mode 100644 index 0000000000..851e1f53cf --- /dev/null +++ b/source3/smbd/auth.c @@ -0,0 +1,275 @@ +/* + Unix SMB/Netbios implementation. + Version 1.9. + Password and authentication handling + Copyright (C) Andrew Tridgell 1992-2000 + Copyright (C) Luke Kenneth Casson Leighton 1996-2000 + 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 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,("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 user is in correct domain if required +****************************************************************************/ + +static BOOL check_domain_match(char *user, char *domain) +{ + /* + * If we aren't serving to trusted domains, we must make sure that + * the validation request comes from an account in the same domain + * as the Samba server + */ + + if (!lp_allow_trusted_domains() && + !strequal(lp_workgroup(), domain) ) { + DEBUG(1, ("check_domain_match: Attempt to connect as user %s from domain %s denied.\n", user, domain)); + return False; + } else { + return True; + } +} + + +uint32 check_password(const auth_usersupplied_info *user_info, auth_serversupplied_info *server_info) +{ + + uint32 nt_status = NT_STATUS_LOGON_FAILURE; + + 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 ((lp_security() == SEC_DOMAIN) && (nt_status != NT_STATUS_NOPROBLEMO)) { + nt_status = check_domain_security(user_info, server_info); + } + + if ((lp_security() == SEC_SERVER) && (nt_status != NT_STATUS_NOPROBLEMO)) { + nt_status = check_server_security(user_info, server_info); + } + + if (lp_security() >= SEC_SERVER) { + 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 (nt_status == NT_STATUS_NOPROBLEMO) { + nt_status = smb_pam_accountcheck(user_info->smb_username.str); + } + + if (nt_status == NT_STATUS_NOPROBLEMO) { + DEBUG(5, ("check_password: Password for user %s suceeded\n", user_info->smb_username.str)); + } else { + DEBUG(3, ("check_password: Password for user %s FAILED with error %d\n", user_info->smb_username.str, nt_status)); + } + return nt_status; + +} + +/**************************************************************************** + COMPATABILITY INTERFACES: + ***************************************************************************/ + +/**************************************************************************** +check if a username/password is OK assuming the password is a 24 byte +SMB hash +return True if the password is correct, False otherwise +****************************************************************************/ + +uint32 pass_check_smb_with_chal(char *user, char *domain, uchar chal[8], + uchar *lm_pwd, int lm_pwd_len, + uchar *nt_pwd, int nt_pwd_len) +{ + + auth_usersupplied_info user_info; + auth_serversupplied_info server_info; + AUTH_STR ourdomain, theirdomain, smb_username, wksta_name; + + ZERO_STRUCT(user_info); + ZERO_STRUCT(ourdomain); + ZERO_STRUCT(theirdomain); + ZERO_STRUCT(smb_username); + ZERO_STRUCT(wksta_name); + + ourdomain.str = lp_workgroup(); + ourdomain.len = strlen(ourdomain.str); + + theirdomain.str = domain; + theirdomain.len = strlen(theirdomain.str); + + user_info.requested_domain = theirdomain; + user_info.domain = ourdomain; + + smb_username.str = user; + smb_username.len = strlen(smb_username.str); + + user_info.requested_username = smb_username; /* For the time-being */ + user_info.smb_username = smb_username; + + user_info.wksta_name.str = client_name(); + user_info.wksta_name.len = strlen(client_name()); + + user_info.wksta_name = wksta_name; + + memcpy(user_info.chal, chal, 8); + + if (lm_pwd_len >= 24 || (lp_encrypted_passwords() && (lm_pwd_len == 0) && lp_null_passwords())) { + /* if 24 bytes long assume it is an encrypted password */ + + user_info.lm_resp.buffer = (uint8 *)lm_pwd; + user_info.lm_resp.len = lm_pwd_len; + user_info.nt_resp.buffer = (uint8 *)nt_pwd; + user_info.nt_resp.len = nt_pwd_len; + + } else { + unsigned char local_lm_response[24]; + unsigned char local_nt_response[24]; + + /* + * Not encrypted - do so. + */ + + DEBUG(5,("pass_check_smb: User passwords not in encrypted format.\n")); + + if (lm_pwd_len > 0) { + SMBencrypt( (uchar *)lm_pwd, user_info.chal, local_lm_response); + user_info.lm_resp.buffer = (uint8 *)local_lm_response; + user_info.lm_resp.len = 24; + + /* This encrypts the lm_pwd feild, which actualy contains the password + rather than the nt_pwd field becouse that contains nothing */ + SMBNTencrypt((uchar *)lm_pwd, user_info.chal, local_nt_response); + user_info.nt_resp.buffer = (uint8 *)local_nt_response; + user_info.nt_resp.len = 24; + } + + user_info.plaintext_password.str = lm_pwd; + user_info.plaintext_password.len = lm_pwd_len; + + } + + return check_password(&user_info, &server_info); +} + +uint32 pass_check_smb(char *user, char *domain, + uchar *lm_pwd, int lm_pwd_len, + uchar *nt_pwd, int nt_pwd_len) +{ + uchar chal[8]; + + if (!last_challenge(chal)) { + generate_random_buffer( chal, 8, False); + } + + return pass_check_smb_with_chal(user, domain, chal, + lm_pwd, lm_pwd_len, + nt_pwd, nt_pwd_len); + +} + +/**************************************************************************** +check if a username/password pair is OK either via the system password +database or the encrypted SMB password database +return True if the password is correct, False otherwise +****************************************************************************/ +BOOL password_ok(char *user, char *password, int pwlen) +{ + + /* + * This hack must die! But until I rewrite the rest of samba + * it must stay - abartlet 2001-08-03 + */ + + if ((pwlen == 0) && !lp_null_passwords()) { + DEBUG(4,("Null passwords not allowed.\n")); + return False; + } + + if (pass_check_smb(user, lp_workgroup(), NULL, 0, password, pwlen) == NT_STATUS_NOPROBLEMO) { + return True; + } + + if (pass_check_smb(user, lp_workgroup(), password, pwlen, NULL, 0) == NT_STATUS_NOPROBLEMO) { + return True; + } + + return False; +} + diff --git a/source3/smbd/auth_domain.c b/source3/smbd/auth_domain.c new file mode 100644 index 0000000000..4bf0a05d7f --- /dev/null +++ b/source3/smbd/auth_domain.c @@ -0,0 +1,417 @@ +/* + 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; + +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. +************************************************************************/ + +uint32 domain_client_validate(const auth_usersupplied_info *user_info, + auth_serversupplied_info *server_info, + char *server) +{ + unsigned char trust_passwd[16]; + fstring remote_machine; + 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; + 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")); + return NT_STATUS_LOGON_FAILURE; + } + + /* + * 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())); + return NT_STATUS_LOGON_FAILURE; + } + + /* Test if machine password is expired and need to be changed */ + if (time(NULL) > last_change_time + lp_machine_password_timeout()) + { + global_machine_password_needs_changing = True; + } + + /* + * 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); + + cli_error(&cli, NULL, NULL, &nt_status); + 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; + + nt_status = domain_client_validate(user_info, server_info, NULL); + + return nt_status; +} + + + diff --git a/source3/smbd/auth_rhosts.c b/source3/smbd/auth_rhosts.c new file mode 100644 index 0000000000..c1bee6247c --- /dev/null +++ b/source3/smbd/auth_rhosts.c @@ -0,0 +1,165 @@ +/* + Unix SMB/Netbios implementation. + Version 1.9. + Main SMB reply routines + Copyright (C) Andrew Tridgell 1992-1998 + + 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; + + +/**************************************************************************** + Read the a hosts.equiv or .rhosts file and check if it + allows this user from this machine. +****************************************************************************/ + +static BOOL check_user_equiv(char *user, char *remote, char *equiv_file) +{ + int plus_allowed = 1; + char *file_host; + char *file_user; + char **lines = file_lines_load(equiv_file, NULL); + int i; + + DEBUG(5, ("check_user_equiv %s %s %s\n", user, remote, equiv_file)); + if (! lines) return False; + for (i=0; lines[i]; i++) { + char *buf = lines[i]; + trim_string(buf," "," "); + + if (buf[0] != '#' && buf[0] != '\n') + { + BOOL is_group = False; + int plus = 1; + char *bp = buf; + if (strcmp(buf, "NO_PLUS\n") == 0) + { + DEBUG(6, ("check_user_equiv NO_PLUS\n")); + plus_allowed = 0; + } + else { + if (buf[0] == '+') + { + bp++; + if (*bp == '\n' && plus_allowed) + { + /* a bare plus means everbody allowed */ + DEBUG(6, ("check_user_equiv everybody allowed\n")); + file_lines_free(lines); + return True; + } + } + else if (buf[0] == '-') + { + bp++; + plus = 0; + } + if (*bp == '@') + { + is_group = True; + bp++; + } + file_host = strtok(bp, " \t\n"); + file_user = strtok(NULL, " \t\n"); + DEBUG(7, ("check_user_equiv %s %s\n", file_host ? file_host : "(null)", + file_user ? file_user : "(null)" )); + if (file_host && *file_host) + { + BOOL host_ok = False; + +#if defined(HAVE_NETGROUP) && defined(HAVE_YP_GET_DEFAULT_DOMAIN) + if (is_group) + { + static char *mydomain = NULL; + if (!mydomain) + yp_get_default_domain(&mydomain); + if (mydomain && innetgr(file_host,remote,user,mydomain)) + host_ok = True; + } +#else + if (is_group) + { + DEBUG(1,("Netgroups not configured\n")); + continue; + } +#endif + + /* is it this host */ + /* the fact that remote has come from a call of gethostbyaddr + * means that it may have the fully qualified domain name + * so we could look up the file version to get it into + * a canonical form, but I would rather just type it + * in full in the equiv file + */ + if (!host_ok && !is_group && strequal(remote, file_host)) + host_ok = True; + + if (!host_ok) + continue; + + /* is it this user */ + if (file_user == 0 || strequal(user, file_user)) + { + DEBUG(5, ("check_user_equiv matched %s%s %s\n", + (plus ? "+" : "-"), file_host, + (file_user ? file_user : ""))); + file_lines_free(lines); + return (plus ? True : False); + } + } + } + } + } + file_lines_free(lines); + return False; +} + + +/**************************************************************************** +check for a possible hosts equiv or rhosts entry for the user +****************************************************************************/ +BOOL check_hosts_equiv(char *user) +{ + char *fname = NULL; + pstring rhostsfile; + struct passwd *pass = Get_Pwnam(user,True); + + if (!pass) + return(False); + + fname = lp_hosts_equiv(); + + /* note: don't allow hosts.equiv on root */ + if (fname && *fname && (pass->pw_uid != 0)) { + if (check_user_equiv(user,client_name(),fname)) + return(True); + } + + if (lp_use_rhosts()) + { + char *home = get_user_home_dir(user); + if (home) { + slprintf(rhostsfile, sizeof(rhostsfile)-1, "%s/.rhosts", home); + if (check_user_equiv(user,client_name(),rhostsfile)) + return(True); + } + } + + return(False); +} diff --git a/source3/smbd/auth_server.c b/source3/smbd/auth_server.c new file mode 100644 index 0000000000..dc1d924b3c --- /dev/null +++ b/source3/smbd/auth_server.c @@ -0,0 +1,244 @@ +/* + Unix SMB/Netbios implementation. + Version 1.9. + Authenticate to a remote server + 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 pstring global_myname; + +/**************************************************************************** + Return the client state structure. +****************************************************************************/ + +struct cli_state *server_client(void) +{ + static struct cli_state pw_cli; + return &pw_cli; +} + +/**************************************************************************** + Support for server level security. +****************************************************************************/ + +struct cli_state *server_cryptkey(void) +{ + struct cli_state *cli; + fstring desthost; + struct in_addr dest_ip; + char *p, *pserver; + BOOL connected_ok = False; + + cli = server_client(); + + if (!cli_initialise(cli)) + return NULL; + + pserver = strdup(lp_passwordserver()); + p = pserver; + + while(next_token( &p, desthost, LIST_SEP, sizeof(desthost))) { + standard_sub_basic(desthost); + strupper(desthost); + + if(!resolve_name( desthost, &dest_ip, 0x20)) { + DEBUG(1,("server_cryptkey: Can't resolve address for %s\n",desthost)); + continue; + } + + if (ismyip(dest_ip)) { + DEBUG(1,("Password server loop - disabling password server %s\n",desthost)); + continue; + } + + if (cli_connect(cli, desthost, &dest_ip)) { + DEBUG(3,("connected to password server %s\n",desthost)); + connected_ok = True; + break; + } + } + + free(pserver); + + if (!connected_ok) { + DEBUG(0,("password server not available\n")); + cli_shutdown(cli); + return NULL; + } + + if (!attempt_netbios_session_request(cli, global_myname, desthost, &dest_ip)) + return NULL; + + DEBUG(3,("got session\n")); + + if (!cli_negprot(cli)) { + DEBUG(1,("%s rejected the negprot\n",desthost)); + cli_shutdown(cli); + return NULL; + } + + if (cli->protocol < PROTOCOL_LANMAN2 || + !(cli->sec_mode & 1)) { + DEBUG(1,("%s isn't in user level security mode\n",desthost)); + cli_shutdown(cli); + return NULL; + } + + DEBUG(3,("password server OK\n")); + + return cli; +} + + +/**************************************************************************** + Validate a password with the password server. +****************************************************************************/ + +static uint32 server_validate(const auth_usersupplied_info *user_info, auth_serversupplied_info *server_info) +{ + struct cli_state *cli; + static unsigned char badpass[24]; + static fstring baduser; + static BOOL tested_password_server = False; + static BOOL bad_password_server = False; + uint32 nt_status = NT_STATUS_LOGON_FAILURE; + + cli = server_client(); + + if (!cli->initialised) { + DEBUG(1,("password server %s is not connected\n", cli->desthost)); + return(NT_STATUS_LOGON_FAILURE); + } + + if(badpass[0] == 0) + memset(badpass, 0x1f, sizeof(badpass)); + + if((user_info->nt_resp.len == sizeof(badpass)) && + !memcmp(badpass, user_info->nt_resp.buffer, sizeof(badpass))) { + /* + * Very unlikely, our random bad password is the same as the users + * password. + */ + memset(badpass, badpass[0]+1, sizeof(badpass)); + } + + if(baduser[0] == 0) { + fstrcpy(baduser, INVALID_USER_PREFIX); + fstrcat(baduser, global_myname); + } + + /* + * Attempt a session setup with a totally incorrect password. + * If this succeeds with the guest bit *NOT* set then the password + * server is broken and is not correctly setting the guest bit. We + * need to detect this as some versions of NT4.x are broken. JRA. + */ + + /* I sure as hell hope that there arn't servers out there that take + * NTLMv2 and have this bug, as we don't test for that... + * - abartlet@samba.org + */ + + if(!tested_password_server) { + if (cli_session_setup(cli, baduser, (char *)badpass, sizeof(badpass), + (char *)badpass, sizeof(badpass), user_info->domain.str)) { + + /* + * We connected to the password server so we + * can say we've tested it. + */ + tested_password_server = True; + + if ((SVAL(cli->inbuf,smb_vwv2) & 1) == 0) { + DEBUG(0,("server_validate: password server %s allows users as non-guest \ +with a bad password.\n", cli->desthost)); + DEBUG(0,("server_validate: This is broken (and insecure) behaviour. Please do not \ +use this machine as the password server.\n")); + cli_ulogoff(cli); + + /* + * Password server has the bug. + */ + bad_password_server = True; + return NT_STATUS_LOGON_FAILURE; + } + cli_ulogoff(cli); + } + } else { + + /* + * We have already tested the password server. + * Fail immediately if it has the bug. + */ + + if(bad_password_server) { + DEBUG(0,("server_validate: [1] password server %s allows users as non-guest \ +with a bad password.\n", cli->desthost)); + DEBUG(0,("server_validate: [1] This is broken (and insecure) behaviour. Please do not \ +use this machine as the password server.\n")); + return NT_STATUS_LOGON_FAILURE; + } + } + + /* + * Now we know the password server will correctly set the guest bit, or is + * not guest enabled, we can try with the real password. + */ + + if (!cli_session_setup(cli, user_info->smb_username.str, + user_info->lm_resp.buffer, + user_info->lm_resp.len, + user_info->nt_resp.buffer, + user_info->nt_resp.len, + user_info->domain.str)) { + DEBUG(1,("password server %s rejected the password\n", cli->desthost)); + nt_status = NT_STATUS_LOGON_FAILURE; + } else { + nt_status = NT_STATUS_NOPROBLEMO; + } + + /* if logged in as guest then reject */ + if ((SVAL(cli->inbuf,smb_vwv2) & 1) != 0) { + DEBUG(1,("password server %s gave us guest only\n", cli->desthost)); + nt_status = NT_STATUS_LOGON_FAILURE; + } + + cli_ulogoff(cli); + + return(nt_status); +} + +/**************************************************************************** + Check for a valid username and password in security=server mode. +****************************************************************************/ + +uint32 check_server_security(const auth_usersupplied_info *user_info, auth_serversupplied_info *server_info) +{ + + if(lp_security() != SEC_SERVER) + return NT_STATUS_LOGON_FAILURE; + + return server_validate(user_info, server_info); + +} + + diff --git a/source3/smbd/auth_smbpasswd.c b/source3/smbd/auth_smbpasswd.c new file mode 100644 index 0000000000..ce0b03d942 --- /dev/null +++ b/source3/smbd/auth_smbpasswd.c @@ -0,0 +1,229 @@ +/* + Unix SMB/Netbios implementation. + Version 1.9. + Password and authentication handling + Copyright (C) Andrew Tridgell 1992-2000 + Copyright (C) Luke Kenneth Casson Leighton 1996-2000 + 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; + +/**************************************************************************** +core of smb password checking routine. +****************************************************************************/ +static BOOL smb_pwd_check_ntlmv1(const uchar *password, + const uchar *part_passwd, + const uchar *c8, + uchar user_sess_key[16]) +{ + /* Finish the encryption of part_passwd. */ + uchar p24[24]; + + if (part_passwd == NULL) { + DEBUG(10,("No password set - DISALLOWING access\n")); + /* No password set - always false ! */ + return False; + } + + SMBOWFencrypt(part_passwd, c8, p24); + if (user_sess_key != NULL) + { + SMBsesskeygen_ntv1(part_passwd, NULL, user_sess_key); + } + + + +#if DEBUG_PASSWORD + DEBUG(100,("Part password (P16) was |")); + dump_data(100, part_passwd, 16); + DEBUG(100,("Password from client was |")); + dump_data(100, password, 24); + DEBUG(100,("Given challenge was |")); + dump_data(100, c8, 8); + DEBUG(100,("Value from encryption was |")); + dump_data(100, p24, 24); +#endif + return (memcmp(p24, password, 24) == 0); +} + +/**************************************************************************** +core of smb password checking routine. +****************************************************************************/ +static BOOL smb_pwd_check_ntlmv2(const uchar *password, size_t pwd_len, + uchar *part_passwd, + uchar const *c8, + const char *user, const char *domain, + char *user_sess_key) +{ + /* Finish the encryption of part_passwd. */ + uchar kr[16]; + uchar resp[16]; + + if (part_passwd == NULL) + { + DEBUG(10,("No password set - DISALLOWING access\n")); + /* No password set - always False */ + return False; + } + + ntv2_owf_gen(part_passwd, user, domain, kr); + SMBOWFencrypt_ntv2(kr, c8, 8, password+16, pwd_len-16, resp); + if (user_sess_key != NULL) + { + SMBsesskeygen_ntv2(kr, resp, user_sess_key); + } + +#if DEBUG_PASSWORD + DEBUG(100,("Part password (P16) was |")); + dump_data(100, part_passwd, 16); + DEBUG(100,("Password from client was |")); + dump_data(100, password, pwd_len); + DEBUG(100,("Given challenge was |")); + dump_data(100, c8, 8); + DEBUG(100,("Value from encryption was |")); + dump_data(100, resp, 16); +#endif + + return (memcmp(resp, password, 16) == 0); +} + + +/**************************************************************************** + Do a specific test for an smb password being correct, given a smb_password and + the lanman and NT responses. +****************************************************************************/ +uint32 smb_password_ok(SAM_ACCOUNT *sampass, const auth_usersupplied_info *user_info, auth_serversupplied_info *server_info) +{ + uint8 *nt_pw, *lm_pw; + + /* Quit if the account was disabled. */ + if(pdb_get_acct_ctrl(sampass) & ACB_DISABLED) { + DEBUG(1,("Account for user '%s' was disabled.\n", user_info->smb_username.str)); + return(NT_STATUS_ACCOUNT_DISABLED); + } + + if (pdb_get_acct_ctrl(sampass) & ACB_PWNOTREQ) + { + if (lp_null_passwords()) + { + DEBUG(3,("Account for user '%s' has no password and null passwords are allowed.\n", user_info->smb_username.str)); + return(NT_STATUS_NOPROBLEMO); + } + else + { + DEBUG(3,("Account for user '%s' has no password and null passwords are NOT allowed.\n", user_info->smb_username.str)); + return(NT_STATUS_LOGON_FAILURE); + } + } + + if (!user_info || !sampass) + return(NT_STATUS_LOGON_FAILURE); + + DEBUG(4,("smb_password_ok: Checking SMB password for user %s\n",user_info->smb_username.str)); + + nt_pw = pdb_get_nt_passwd(sampass); + + if (nt_pw != NULL) { + if ((user_info->nt_resp.len > 24 )) { + /* We have the NT MD4 hash challenge available - see if we can + use it (ie. does it exist in the smbpasswd file). + */ + DEBUG(4,("smb_password_ok: Checking NTLMv2 password\n")); + if (smb_pwd_check_ntlmv2( user_info->nt_resp.buffer, + user_info->nt_resp.len, + nt_pw, + user_info->chal, user_info->requested_username.str, + user_info->requested_domain.str, + server_info->session_key)) + { + return NT_STATUS_NOPROBLEMO; + } + DEBUG(4,("smb_password_ok: NT MD4 password check failed\n")); + + } else if (lp_ntlm_auth() && (user_info->nt_resp.len == 24 )) { + /* We have the NT MD4 hash challenge available - see if we can + use it (ie. does it exist in the smbpasswd file). + */ + DEBUG(4,("smb_password_ok: Checking NT MD4 password\n")); + if (smb_pwd_check_ntlmv1(user_info->nt_resp.buffer, + nt_pw, user_info->chal, + server_info->session_key)) { + DEBUG(4,("smb_password_ok: NT MD4 password check succeeded\n")); + return NT_STATUS_NOPROBLEMO; + } else { + DEBUG(4,("smb_password_ok: NT MD4 password check failed\n")); + return NT_STATUS_WRONG_PASSWORD; + } + } + } + + lm_pw = pdb_get_lanman_passwd(sampass); + + if(lp_lanman_auth() && (lm_pw != NULL) && (user_info->lm_resp.len == 24 )) { + DEBUG(4,("smb_password_ok: Checking LM password\n")); + if (smb_pwd_check_ntlmv1(user_info->lm_resp.buffer, + lm_pw, user_info->chal, + server_info->session_key)) { + DEBUG(4,("smb_password_ok: LM password check succeeded\n")); + return NT_STATUS_NOPROBLEMO; + } else { + DEBUG(4,("smb_password_ok: LM password check failed\n")); + return NT_STATUS_WRONG_PASSWORD; + } + } + + return NT_STATUS_LOGON_FAILURE; +} + + +/**************************************************************************** +check if a username/password is OK assuming the password is a 24 byte +SMB hash +return True if the password is correct, False otherwise +****************************************************************************/ + +uint32 check_smbpasswd_security(const auth_usersupplied_info *user_info, auth_serversupplied_info *server_info) +{ + SAM_ACCOUNT *sampass=NULL; + BOOL ret; + uint32 nt_status; + + pdb_init_sam(&sampass); + + /* get the account information */ + ret = pdb_getsampwnam(sampass, user_info->smb_username.str); + if (ret == False) + { + DEBUG(1,("Couldn't find user '%s' in passdb file.\n", user_info->smb_username.str)); + pdb_free_sam(sampass); + 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); + } + + pdb_free_sam(sampass); + return nt_status; +} + + diff --git a/source3/smbd/auth_util.c b/source3/smbd/auth_util.c new file mode 100644 index 0000000000..1c12a4322d --- /dev/null +++ b/source3/smbd/auth_util.c @@ -0,0 +1,141 @@ +/* + Unix SMB/Netbios implementation. + Version 1.9. + Authentication utility functions + 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; + +/* Data to do lanman1/2 password challenge. */ +static unsigned char saved_challenge[8]; +static BOOL challenge_sent=False; + +/******************************************************************* +Get the next challenge value - no repeats. +********************************************************************/ +void generate_next_challenge(char *challenge) +{ + unsigned char buf[8]; + + generate_random_buffer(buf,8,False); + memcpy(saved_challenge, buf, 8); + memcpy(challenge,buf,8); + challenge_sent = True; +} + +/******************************************************************* +set the last challenge sent, usually from a password server +********************************************************************/ +BOOL set_challenge(unsigned char *challenge) +{ + memcpy(saved_challenge,challenge,8); + challenge_sent = True; + return(True); +} + +/******************************************************************* +get the last challenge sent +********************************************************************/ +BOOL last_challenge(unsigned char *challenge) +{ + if (!challenge_sent) return(False); + memcpy(challenge,saved_challenge,8); + return(True); +} + + +/**************************************************************************** + Create a UNIX user on demand. +****************************************************************************/ + +static int smb_create_user(char *unix_user, char *homedir) +{ + pstring add_script; + int ret; + + pstrcpy(add_script, lp_adduser_script()); + if (! *add_script) return -1; + all_string_sub(add_script, "%u", unix_user, sizeof(pstring)); + if (homedir) + all_string_sub(add_script, "%H", homedir, sizeof(pstring)); + ret = smbrun(add_script,NULL); + DEBUG(3,("smb_create_user: Running the command `%s' gave %d\n",add_script,ret)); + return ret; +} + +/**************************************************************************** + Delete a UNIX user on demand. +****************************************************************************/ + +static int smb_delete_user(char *unix_user) +{ + pstring del_script; + int ret; + + pstrcpy(del_script, lp_deluser_script()); + if (! *del_script) return -1; + all_string_sub(del_script, "%u", unix_user, sizeof(pstring)); + ret = smbrun(del_script,NULL); + DEBUG(3,("smb_delete_user: Running the command `%s' gave %d\n",del_script,ret)); + return ret; +} + +/**************************************************************************** + Add and Delete UNIX users on demand, based on NT_STATUS codes. +****************************************************************************/ + +void smb_user_control(char *unix_user, uint32 nt_status) +{ + struct passwd *pwd=NULL; + + if(nt_status == NT_STATUS_NOPROBLEMO) { + /* + * User validated ok against Domain controller. + * If the admin wants us to try and create a UNIX + * user on the fly, do so. + */ + if(lp_adduser_script() && !(pwd = smb_getpwnam(unix_user,True))) + smb_create_user(unix_user, NULL); + + if(lp_adduser_script() && pwd) { + SMB_STRUCT_STAT st; + + /* + * Also call smb_create_user if the users home directory + * doesn't exist. Used with winbindd to allow the script to + * create the home directory for a user mapped with winbindd. + */ + + if (pwd->pw_dir && (sys_stat(pwd->pw_dir, &st) == -1) && (errno == ENOENT)) + smb_create_user(unix_user, pwd->pw_dir); + } + + } else if (nt_status == NT_STATUS_NO_SUCH_USER) { + /* + * User failed to validate ok against Domain controller. + * If the failure was "user doesn't exist" and admin + * wants us to try and delete that UNIX user on the fly, + * do so. + */ + if(lp_deluser_script() && smb_getpwnam(unix_user,True)) + smb_delete_user(unix_user); + } + +} diff --git a/source3/smbd/negprot.c b/source3/smbd/negprot.c index de6f5d789f..6410aa2da6 100644 --- a/source3/smbd/negprot.c +++ b/source3/smbd/negprot.c @@ -179,7 +179,10 @@ static int reply_nt1(char *outbuf) char *p, *q; if (lp_security() == SEC_SERVER) { + DEBUG(5,("attempting password server validation\n")); cli = server_cryptkey(); + } else { + DEBUG(5,("attempting local password validation\n")); } if (cli) { diff --git a/source3/smbd/password.c b/source3/smbd/password.c index 743d6ebffe..4aa5a0211e 100644 --- a/source3/smbd/password.c +++ b/source3/smbd/password.c @@ -25,52 +25,12 @@ extern int DEBUGLEVEL; extern int Protocol; extern struct in_addr ipzero; -BOOL global_machine_password_needs_changing = False; - /* users from session setup */ static pstring session_users=""; extern pstring global_myname; extern fstring global_myworkgroup; -/* Data to do lanman1/2 password challenge. */ -static unsigned char saved_challenge[8]; -static BOOL challenge_sent=False; - -/******************************************************************* -Get the next challenge value - no repeats. -********************************************************************/ -void generate_next_challenge(char *challenge) -{ - unsigned char buf[8]; - - generate_random_buffer(buf,8,False); - - memcpy(saved_challenge, buf, 8); - memcpy(challenge,buf,8); - challenge_sent = True; -} - -/******************************************************************* -set the last challenge sent, usually from a password server -********************************************************************/ -BOOL set_challenge(unsigned char *challenge) -{ - memcpy(saved_challenge,challenge,8); - challenge_sent = True; - return(True); -} - -/******************************************************************* -get the last challenge sent -********************************************************************/ -static BOOL last_challenge(unsigned char *challenge) -{ - if (!challenge_sent) return(False); - memcpy(challenge,saved_challenge,8); - return(True); -} - /* this holds info on user ids that are already validated for this VC */ static user_struct *validated_users; static int next_vuid = VUID_OFFSET; @@ -342,287 +302,6 @@ void add_session_user(char *user) /**************************************************************************** -update the encrypted smbpasswd file from the plaintext username and password -*****************************************************************************/ -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; -} - -/**************************************************************************** -core of smb password checking routine. -****************************************************************************/ -BOOL smb_password_check(char *password, unsigned char *part_passwd, unsigned char *c8) -{ - /* Finish the encryption of part_passwd. */ - unsigned char p21[21]; - unsigned char p24[24]; - - if (part_passwd == NULL) - { - DEBUG(10,("No password set - allowing access\n")); - - /* No password set - always true ! */ - return 1; - } - - memset(p21,'\0',21); - memcpy(p21,part_passwd,16); - E_P24(p21, c8, p24); -#if DEBUG_PASSWORD - { - int i; - DEBUG(100,("Part password (P16) was |")); - for(i = 0; i < 16; i++) - DEBUG(100,("%X ", (unsigned char)part_passwd[i])); - DEBUG(100,("|\n")); - DEBUG(100,("Password from client was |")); - for(i = 0; i < 24; i++) - DEBUG(100,("%X ", (unsigned char)password[i])); - DEBUG(100,("|\n")); - DEBUG(100,("Given challenge was |")); - for(i = 0; i < 8; i++) - DEBUG(100,("%X ", (unsigned char)c8[i])); - DEBUG(100,("|\n")); - DEBUG(100,("Value from encryption was |")); - for(i = 0; i < 24; i++) - DEBUG(100,("%X ", (unsigned char)p24[i])); - DEBUG(100,("|\n")); - } -#endif - return (memcmp(p24, password, 24) == 0); -} - -/**************************************************************************** - Do a specific test for an smb password being correct, given a smb_password and - the lanman and NT responses. -****************************************************************************/ -BOOL smb_password_ok(SAM_ACCOUNT *sampass, uchar chal[8], - uchar lm_pass[24], uchar nt_pass[24]) -{ - uchar challenge[8]; - char* user_name; - uint8 *nt_pw, *lm_pw; - - if (!lm_pass || !sampass) - return(False); - - user_name = pdb_get_username(sampass); - - DEBUG(4,("smb_password_ok: Checking SMB password for user %s\n",user_name)); - - if(pdb_get_acct_ctrl(sampass) & ACB_DISABLED) { - DEBUG(1,("smb_password_ok: account for user %s was disabled.\n", user_name)); - return(False); - } - - if (chal == NULL) { - DEBUG(5,("smb_password_ok: use last SMBnegprot challenge\n")); - if (!last_challenge(challenge)) { - DEBUG(1,("smb_password_ok: no challenge done - password failed\n")); - return False; - } - } else { - DEBUG(5,("smb_password_ok: challenge received\n")); - memcpy(challenge, chal, 8); - } - - nt_pw = pdb_get_nt_passwd(sampass); - - if ((Protocol >= PROTOCOL_NT1) && (nt_pw != NULL)) { - /* We have the NT MD4 hash challenge available - see if we can - use it (ie. does it exist in the smbpasswd file). - */ - DEBUG(4,("smb_password_ok: Checking NT MD4 password\n")); - if (smb_password_check((char *)nt_pass, (uchar *)nt_pw, challenge)) { - DEBUG(4,("smb_password_ok: NT MD4 password check succeeded\n")); - return(True); - } - DEBUG(4,("smb_password_ok: NT MD4 password check failed\n")); - } - - /* Try against the lanman password. pdb_get_lanman_passwd(sampass) == NULL - means no password, allow access. */ - - lm_pw = pdb_get_lanman_passwd(sampass); - - if((lm_pw == NULL) && (pdb_get_acct_ctrl(sampass) & ACB_PWNOTREQ)) - { - DEBUG(4,("smb_password_ok: no password required for user %s\n",user_name)); - return True; - } - - if(lp_lanman_auth() && (lm_pw != NULL)) { - DEBUG(4,("smb_password_ok: Checking LM password\n")); - if(smb_password_check((char *)lm_pass,(uchar *)lm_pw, challenge)) { - DEBUG(4,("smb_password_ok: LM password check succeeded\n")); - return(True); - } - DEBUG(4,("smb_password_ok: LM password check failed\n")); - } - - return False; -} - - -/**************************************************************************** -check if a username/password is OK assuming the password is a 24 byte -SMB hash -return True if the password is correct, False otherwise -****************************************************************************/ - -BOOL pass_check_smb(char *user, char *domain, uchar *chal, - uchar *lm_pwd, uchar *nt_pwd) -{ - struct passwd *pass; - SAM_ACCOUNT *sampass=NULL; - BOOL ret; - - if (!lm_pwd || !nt_pwd) - { - return(False); - } - - /* FIXME! this code looks to be unnecessary now that the passdb - validates that the username exists and has a valid uid */ - - /* I don't get this call here. I think it should be moved. - Need to check on it. --jerry */ - pass = smb_getpwnam(user,True); - - if (pass == NULL) - { - DEBUG(1,("Couldn't find user '%s' in UNIX password database.\n",user)); - return(False); - } - - pdb_init_sam(&sampass); - - /* get the account information */ - ret = pdb_getsampwnam(sampass, user); - if (ret == False) - { - DEBUG(1,("Couldn't find user '%s' in passdb file.\n", user)); - pdb_free_sam(sampass); - return(False); - } - - /* Quit if the account was disabled. */ - if(pdb_get_acct_ctrl(sampass) & ACB_DISABLED) { - DEBUG(1,("Account for user '%s' was disabled.\n", user)); - pdb_free_sam(sampass); - return(False); - } - - /* Ensure the uid's match - FIXME! This also seems unnecessary --jerry */ -#if 0 /* GWC */ - if (smb_pass->smb_userid != pass->pw_uid) - { - DEBUG(0,("Error : UNIX and SMB uids in password files do not match for user '%s'!\n", user)); - pdb_free_sam(sampass); - return(False); - } -#endif - - if (pdb_get_acct_ctrl(sampass) & ACB_PWNOTREQ) - { - if (lp_null_passwords()) - { - DEBUG(3,("Account for user '%s' has no password and null passwords are allowed.\n", user)); - pdb_free_sam(sampass); - return(True); - } - else - { - DEBUG(3,("Account for user '%s' has no password and null passwords are NOT allowed.\n", user)); - pdb_free_sam(sampass); - return(False); - } - } - - if (smb_password_ok(sampass, chal, lm_pwd, nt_pwd)) - { - pdb_free_sam(sampass); - return(True); - } - - DEBUG(2,("pass_check_smb failed - invalid password for user [%s]\n", user)); - pdb_free_sam(sampass); - return False; -} - -/**************************************************************************** -check if a username/password pair is OK either via the system password -database or the encrypted SMB password database -return True if the password is correct, False otherwise -****************************************************************************/ -BOOL password_ok(char *user, char *password, int pwlen) -{ - BOOL ret; - - if ((pwlen == 0) && !lp_null_passwords()) { - DEBUG(4,("Null passwords not allowed.\n")); - return False; - } - - if (pwlen == 24 || (lp_encrypted_passwords() && (pwlen == 0) && lp_null_passwords())) { - /* if 24 bytes long assume it is an encrypted password */ - uchar challenge[8]; - - if (!last_challenge(challenge)) { - DEBUG(0,("Error: challenge not done for user=%s\n", user)); - return False; - } - - ret = pass_check_smb(user, global_myworkgroup, - challenge, (uchar *)password, (uchar *)password); - - /* - * Try with PAM (may not be compiled in - returns True if not. JRA). - * FIXME ! Should this be called if we're using winbindd ? What about - * non-local accounts ? JRA. - */ - - if (ret) - return (smb_pam_accountcheck(user) == NT_STATUS_NOPROBLEMO); - } - - return pass_check(user, password, pwlen, - lp_update_encrypted() ? - update_smbpassword_file : NULL); -} - -/**************************************************************************** check if a username is valid ****************************************************************************/ BOOL user_ok(char *user,int snum) @@ -660,9 +339,6 @@ BOOL user_ok(char *user,int snum) return(ret); } - - - /**************************************************************************** validate a group username entry. Return the username or NULL ****************************************************************************/ @@ -857,13 +533,6 @@ and given password ok\n", user)); ok = True; } - /* check for a rhosts entry */ - if (!ok && user_ok(user,snum) && check_hosts_equiv(user)) { - ok = True; - DEBUG(3,("authorise_login: ACCEPTED: hosts equiv or rhosts entry for %s\n", - user)); - } - /* check the user= fields and the given password */ if (!ok && lp_username(snum)) { char *auser; @@ -918,744 +587,3 @@ and given password ok (%s)\n", user)); return(ok); } - -/**************************************************************************** - Read the a hosts.equiv or .rhosts file and check if it - allows this user from this machine. -****************************************************************************/ - -static BOOL check_user_equiv(char *user, char *remote, char *equiv_file) -{ - int plus_allowed = 1; - char *file_host; - char *file_user; - char **lines = file_lines_load(equiv_file, NULL); - int i; - - DEBUG(5, ("check_user_equiv %s %s %s\n", user, remote, equiv_file)); - if (! lines) return False; - for (i=0; lines[i]; i++) { - char *buf = lines[i]; - trim_string(buf," "," "); - - if (buf[0] != '#' && buf[0] != '\n') - { - BOOL is_group = False; - int plus = 1; - char *bp = buf; - if (strcmp(buf, "NO_PLUS\n") == 0) - { - DEBUG(6, ("check_user_equiv NO_PLUS\n")); - plus_allowed = 0; - } - else { - if (buf[0] == '+') - { - bp++; - if (*bp == '\n' && plus_allowed) - { - /* a bare plus means everbody allowed */ - DEBUG(6, ("check_user_equiv everybody allowed\n")); - file_lines_free(lines); - return True; - } - } - else if (buf[0] == '-') - { - bp++; - plus = 0; - } - if (*bp == '@') - { - is_group = True; - bp++; - } - file_host = strtok(bp, " \t\n"); - file_user = strtok(NULL, " \t\n"); - DEBUG(7, ("check_user_equiv %s %s\n", file_host ? file_host : "(null)", - file_user ? file_user : "(null)" )); - if (file_host && *file_host) - { - BOOL host_ok = False; - -#if defined(HAVE_NETGROUP) && defined(HAVE_YP_GET_DEFAULT_DOMAIN) - if (is_group) - { - static char *mydomain = NULL; - if (!mydomain) - yp_get_default_domain(&mydomain); - if (mydomain && innetgr(file_host,remote,user,mydomain)) - host_ok = True; - } -#else - if (is_group) - { - DEBUG(1,("Netgroups not configured\n")); - continue; - } -#endif - - /* is it this host */ - /* the fact that remote has come from a call of gethostbyaddr - * means that it may have the fully qualified domain name - * so we could look up the file version to get it into - * a canonical form, but I would rather just type it - * in full in the equiv file - */ - if (!host_ok && !is_group && strequal(remote, file_host)) - host_ok = True; - - if (!host_ok) - continue; - - /* is it this user */ - if (file_user == 0 || strequal(user, file_user)) - { - DEBUG(5, ("check_user_equiv matched %s%s %s\n", - (plus ? "+" : "-"), file_host, - (file_user ? file_user : ""))); - file_lines_free(lines); - return (plus ? True : False); - } - } - } - } - } - file_lines_free(lines); - return False; -} - - -/**************************************************************************** -check for a possible hosts equiv or rhosts entry for the user -****************************************************************************/ -BOOL check_hosts_equiv(char *user) -{ - char *fname = NULL; - pstring rhostsfile; - struct passwd *pass = Get_Pwnam(user,True); - - if (!pass) - return(False); - - fname = lp_hosts_equiv(); - - /* note: don't allow hosts.equiv on root */ - if (fname && *fname && (pass->pw_uid != 0)) { - if (check_user_equiv(user,client_name(),fname)) - return(True); - } - - if (lp_use_rhosts()) - { - char *home = get_user_home_dir(user); - if (home) { - slprintf(rhostsfile, sizeof(rhostsfile)-1, "%s/.rhosts", home); - if (check_user_equiv(user,client_name(),rhostsfile)) - return(True); - } - } - - return(False); -} - - -/**************************************************************************** - Return the client state structure. -****************************************************************************/ - -struct cli_state *server_client(void) -{ - static struct cli_state pw_cli; - return &pw_cli; -} - -/**************************************************************************** - Support for server level security. -****************************************************************************/ - -struct cli_state *server_cryptkey(void) -{ - struct cli_state *cli; - fstring desthost; - struct in_addr dest_ip; - char *p, *pserver; - BOOL connected_ok = False; - - cli = server_client(); - - if (!cli_initialise(cli)) - return NULL; - - pserver = strdup(lp_passwordserver()); - p = pserver; - - while(next_token( &p, desthost, LIST_SEP, sizeof(desthost))) { - standard_sub_basic(desthost); - strupper(desthost); - - if(!resolve_name( desthost, &dest_ip, 0x20)) { - DEBUG(1,("server_cryptkey: Can't resolve address for %s\n",desthost)); - continue; - } - - if (ismyip(dest_ip)) { - DEBUG(1,("Password server loop - disabling password server %s\n",desthost)); - continue; - } - - if (cli_connect(cli, desthost, &dest_ip)) { - DEBUG(3,("connected to password server %s\n",desthost)); - connected_ok = True; - break; - } - } - - free(pserver); - - if (!connected_ok) { - DEBUG(0,("password server not available\n")); - cli_shutdown(cli); - return NULL; - } - - if (!attempt_netbios_session_request(cli, global_myname, desthost, &dest_ip)) - return NULL; - - DEBUG(3,("got session\n")); - - if (!cli_negprot(cli)) { - DEBUG(1,("%s rejected the negprot\n",desthost)); - cli_shutdown(cli); - return NULL; - } - - if (cli->protocol < PROTOCOL_LANMAN2 || - !(cli->sec_mode & 1)) { - DEBUG(1,("%s isn't in user level security mode\n",desthost)); - cli_shutdown(cli); - return NULL; - } - - DEBUG(3,("password server OK\n")); - - return cli; -} - -/**************************************************************************** - Validate a password with the password server. -****************************************************************************/ - -BOOL server_validate(char *user, char *domain, - char *pass, int passlen, - char *ntpass, int ntpasslen) -{ - struct cli_state *cli; - static unsigned char badpass[24]; - static fstring baduser; - static BOOL tested_password_server = False; - static BOOL bad_password_server = False; - - cli = server_client(); - - if (!cli->initialised) { - DEBUG(1,("password server %s is not connected\n", cli->desthost)); - return(False); - } - - if(badpass[0] == 0) - memset(badpass, 0x1f, sizeof(badpass)); - - if((passlen == sizeof(badpass)) && !memcmp(badpass, pass, passlen)) { - /* - * Very unlikely, our random bad password is the same as the users - * password. - */ - memset(badpass, badpass[0]+1, sizeof(badpass)); - } - - if(baduser[0] == 0) { - fstrcpy(baduser, INVALID_USER_PREFIX); - fstrcat(baduser, global_myname); - } - - /* - * Attempt a session setup with a totally incorrect password. - * If this succeeds with the guest bit *NOT* set then the password - * server is broken and is not correctly setting the guest bit. We - * need to detect this as some versions of NT4.x are broken. JRA. - */ - - if(!tested_password_server) { - if (cli_session_setup(cli, baduser, (char *)badpass, sizeof(badpass), - (char *)badpass, sizeof(badpass), domain)) { - - /* - * We connected to the password server so we - * can say we've tested it. - */ - tested_password_server = True; - - if ((SVAL(cli->inbuf,smb_vwv2) & 1) == 0) { - DEBUG(0,("server_validate: password server %s allows users as non-guest \ -with a bad password.\n", cli->desthost)); - DEBUG(0,("server_validate: This is broken (and insecure) behaviour. Please do not \ -use this machine as the password server.\n")); - cli_ulogoff(cli); - - /* - * Password server has the bug. - */ - bad_password_server = True; - return False; - } - cli_ulogoff(cli); - } - } else { - - /* - * We have already tested the password server. - * Fail immediately if it has the bug. - */ - - if(bad_password_server) { - DEBUG(0,("server_validate: [1] password server %s allows users as non-guest \ -with a bad password.\n", cli->desthost)); - DEBUG(0,("server_validate: [1] This is broken (and insecure) behaviour. Please do not \ -use this machine as the password server.\n")); - return False; - } - } - - /* - * Now we know the password server will correctly set the guest bit, or is - * not guest enabled, we can try with the real password. - */ - - if (!cli_session_setup(cli, user, pass, passlen, ntpass, ntpasslen, domain)) { - DEBUG(1,("password server %s rejected the password\n", cli->desthost)); - return False; - } - - /* if logged in as guest then reject */ - if ((SVAL(cli->inbuf,smb_vwv2) & 1) != 0) { - DEBUG(1,("password server %s gave us guest only\n", cli->desthost)); - cli_ulogoff(cli); - return(False); - } - - cli_ulogoff(cli); - - return(True); -} - -/*********************************************************************** - 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. -************************************************************************/ - -BOOL domain_client_validate( char *user, char *domain, - char *smb_apasswd, int smb_apasslen, - char *smb_ntpasswd, int smb_ntpasslen, - BOOL *user_exists, char *server) -{ - unsigned char local_challenge[8]; - unsigned char local_lm_response[24]; - unsigned char local_nt_response[24]; - unsigned char trust_passwd[16]; - fstring remote_machine; - 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; - time_t last_change_time; - - if(user_exists != NULL) - *user_exists = True; /* Only set false on a very specific error. */ - - /* - * 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( domain, global_myname)) { - DEBUG(3,("domain_client_validate: Requested domain was for this machine.\n")); - return False; - } - - /* - * Next, check that the passwords given were encrypted. - */ - - if(((smb_apasslen != 24) && (smb_apasslen != 0)) || - ((smb_ntpasslen != 24) && (smb_ntpasslen != 0))) { - - /* - * Not encrypted - do so. - */ - - DEBUG(5,("domain_client_validate: User passwords not in encrypted format.\n")); - generate_random_buffer( local_challenge, 8, False); - SMBencrypt( (uchar *)smb_apasswd, local_challenge, local_lm_response); - SMBNTencrypt((uchar *)smb_ntpasswd, local_challenge, local_nt_response); - smb_apasslen = 24; - smb_ntpasslen = 24; - smb_apasswd = (char *)local_lm_response; - smb_ntpasswd = (char *)local_nt_response; - } else { - - /* - * Encrypted - get the challenge we sent for these - * responses. - */ - - if (!last_challenge(local_challenge)) { - DEBUG(0,("domain_client_validate: no challenge done - password failed\n")); - return False; - } - } - - /* - * Get the machine account password for our primary domain - */ - if (!secrets_fetch_trust_account_password(global_myworkgroup, trust_passwd, &last_change_time)) - { - DEBUG(0, ("domain_client_validate: could not fetch trust account password for domain %s\n", global_myworkgroup)); - return False; - } - - /* Test if machine password is expired and need to be changed */ - if (time(NULL) > last_change_time + lp_machine_password_timeout()) - { - global_machine_password_needs_changing = True; - } - - /* - * 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 False; - } - - /* 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, domain, user, smb_uid_low, (char *)local_challenge, - ((smb_apasslen != 0) ? smb_apasswd : NULL), - ((smb_ntpasslen != 0) ? smb_ntpasswd : NULL), - &ctr, &info3) == False) { - uint32 nt_rpc_err; - - cli_error(&cli, NULL, NULL, &nt_rpc_err); - DEBUG(0,("domain_client_validate: unable to validate password for user %s in domain \ -%s to Domain controller %s. Error was %s.\n", user, domain, remote_machine, cli_errstr(&cli))); - cli_nt_session_close(&cli); - cli_ulogoff(&cli); - cli_shutdown(&cli); - - if((nt_rpc_err == NT_STATUS_NO_SUCH_USER) && (user_exists != NULL)) - *user_exists = False; - - return False; - } - - /* - * 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(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))); - cli_nt_session_close(&cli); - cli_ulogoff(&cli); - cli_shutdown(&cli); - return False; - } -#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 True; -} diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c index 324734a79d..ab3fba9830 100644 --- a/source3/smbd/reply.c +++ b/source3/smbd/reply.c @@ -434,6 +434,11 @@ int reply_ioctl(connection_struct *conn, } /**************************************************************************** + This function breaks the authentication split. It needs sorting out. + I can't see why we can't hadle this INSIDE the check_password, as in then + end all it does it spit out an nt_status code. + ****************************************************************************/ +/**************************************************************************** always return an error: it's just a matter of which one... ****************************************************************************/ static int session_trust_account(connection_struct *conn, char *inbuf, char *outbuf, char *user, @@ -444,7 +449,40 @@ static int session_trust_account(connection_struct *conn, char *inbuf, char *out SAM_ACCOUNT *sam_trust_acct = NULL; uint16 acct_ctrl; BOOL ret; - + auth_usersupplied_info user_info; + auth_serversupplied_info server_info; + AUTH_STR domain, smb_username, wksta_name; + + ZERO_STRUCT(user_info); + ZERO_STRUCT(server_info); + ZERO_STRUCT(domain); + ZERO_STRUCT(smb_username); + ZERO_STRUCT(wksta_name); + + domain.str = lp_workgroup(); + domain.len = strlen(domain.str); + + user_info.requested_domain = domain; + user_info.domain = domain; + + smb_username.str = user; + smb_username.len = strlen(smb_username.str); + + user_info.requested_username = smb_username; /* For the time-being */ + user_info.smb_username = smb_username; + + user_info.wksta_name = wksta_name; + + user_info.lm_resp.buffer = (uint8 *)smb_passwd; + user_info.lm_resp.len = smb_passlen; + user_info.nt_resp.buffer = (uint8 *)smb_nt_passwd; + user_info.nt_resp.len = smb_nt_passlen; + + if (!last_challenge(user_info.chal)) { + DEBUG(1,("smb_password_ok: no challenge done - password failed\n")); + return NT_STATUS_LOGON_FAILURE; + } + pdb_init_sam(&sam_trust_acct); if (lp_security() == SEC_USER) { @@ -470,7 +508,7 @@ static int session_trust_account(connection_struct *conn, char *inbuf, char *out return(ERROR(0, NT_STATUS_LOGON_FAILURE)); } - if (!smb_password_ok(sam_trust_acct, NULL, (unsigned char *)smb_passwd, (unsigned char *)smb_nt_passwd)) { + if (!smb_password_ok(sam_trust_acct, &user_info, &server_info)) { DEBUG(0,("session_trust_account: Trust Account %s - password failed\n", user)); SSVAL(outbuf, smb_flg2, SVAL(outbuf, smb_flg2) | FLAGS2_32_BIT_ERROR_CODES); pdb_free_sam(sam_trust_acct); @@ -504,173 +542,6 @@ static int session_trust_account(connection_struct *conn, char *inbuf, char *out } /**************************************************************************** - Create a UNIX user on demand. -****************************************************************************/ - -int smb_create_user(char *unix_user, char *homedir) -{ - pstring add_script; - int ret; - - pstrcpy(add_script, lp_adduser_script()); - if (! *add_script) return -1; - all_string_sub(add_script, "%u", unix_user, sizeof(pstring)); - if (homedir) - all_string_sub(add_script, "%H", homedir, sizeof(pstring)); - ret = smbrun(add_script,NULL); - DEBUG(3,("smb_create_user: Running the command `%s' gave %d\n",add_script,ret)); - return ret; -} - -/**************************************************************************** - Delete a UNIX user on demand. -****************************************************************************/ - -static int smb_delete_user(char *unix_user) -{ - pstring del_script; - int ret; - - pstrcpy(del_script, lp_deluser_script()); - if (! *del_script) return -1; - all_string_sub(del_script, "%u", unix_user, sizeof(pstring)); - ret = smbrun(del_script,NULL); - DEBUG(3,("smb_delete_user: Running the command `%s' gave %d\n",del_script,ret)); - return ret; -} - -/**************************************************************************** - Check user is in correct domain if required -****************************************************************************/ - -static BOOL check_domain_match(char *user, char *domain) -{ - /* - * If we aren't serving to trusted domains, we must make sure that - * the validation request comes from an account in the same domain - * as the Samba server - */ - - if (!lp_allow_trusted_domains() && - !strequal(lp_workgroup(), domain) ) { - DEBUG(1, ("check_domain_match: Attempt to connect as user %s from domain %s denied.\n", user, domain)); - return False; - } else { - return True; - } -} - -/**************************************************************************** - Check for a valid username and password in security=server mode. -****************************************************************************/ - -static BOOL check_server_security(char *orig_user, char *domain, char *unix_user, - char *smb_apasswd, int smb_apasslen, - char *smb_ntpasswd, int smb_ntpasslen) -{ - BOOL ret = False; - - if(lp_security() != SEC_SERVER) - return False; - - if (!check_domain_match(orig_user, domain)) - return False; - - ret = server_validate(orig_user, domain, - smb_apasswd, smb_apasslen, - smb_ntpasswd, smb_ntpasslen); - if(ret) { - struct passwd *pwd=NULL; - - /* - * User validated ok against Domain controller. - * If the admin wants us to try and create a UNIX - * user on the fly, do so. - * Note that we can never delete users when in server - * level security as we never know if it was a failure - * due to a bad password, or the user really doesn't exist. - */ - if(lp_adduser_script() && !(pwd = smb_getpwnam(unix_user,True))) { - smb_create_user(unix_user, NULL); - } - - if(lp_adduser_script() && pwd) { - SMB_STRUCT_STAT st; - - /* - * Also call smb_create_user if the users home directory - * doesn't exist. Used with winbindd to allow the script to - * create the home directory for a user mapped with winbindd. - */ - - if (pwd->pw_shell && (sys_stat(pwd->pw_dir, &st) == -1) && (errno == ENOENT)) - smb_create_user(unix_user, pwd->pw_dir); - } - } - - return ret; -} - -/**************************************************************************** - Check for a valid username and password in security=domain mode. -****************************************************************************/ - -static BOOL check_domain_security(char *orig_user, char *domain, char *unix_user, - char *smb_apasswd, int smb_apasslen, - char *smb_ntpasswd, int smb_ntpasslen) -{ - BOOL ret = False; - BOOL user_exists = True; - struct passwd *pwd=NULL; - - if(lp_security() != SEC_DOMAIN) - return False; - - if (!check_domain_match(orig_user, domain)) - return False; - - ret = domain_client_validate(orig_user, domain, - smb_apasswd, smb_apasslen, - smb_ntpasswd, smb_ntpasslen, - &user_exists, NULL); - - if(ret) { - /* - * User validated ok against Domain controller. - * If the admin wants us to try and create a UNIX - * user on the fly, do so. - */ - if(user_exists && lp_adduser_script() && !(pwd = smb_getpwnam(unix_user,True))) - smb_create_user(unix_user, NULL); - - if(lp_adduser_script() && pwd) { - SMB_STRUCT_STAT st; - - /* - * Also call smb_create_user if the users home directory - * doesn't exist. Used with winbindd to allow the script to - * create the home directory for a user mapped with winbindd. - */ - - if (pwd->pw_dir && (sys_stat(pwd->pw_dir, &st) == -1) && (errno == ENOENT)) - smb_create_user(unix_user, pwd->pw_dir); - } - - } else { - /* - * User failed to validate ok against Domain controller. - * If the failure was "user doesn't exist" and admin - * wants us to try and delete that UNIX user on the fly, - * do so. - */ - if(!user_exists && lp_deluser_script() && smb_getpwnam(unix_user,True)) - smb_delete_user(unix_user); - } - - return ret; -} - -/**************************************************************************** Return a bad password error configured for the correct client type. ****************************************************************************/ @@ -701,8 +572,7 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,int pstring smb_apasswd; int smb_ntpasslen = 0; pstring smb_ntpasswd; - BOOL valid_nt_password = False; - BOOL valid_lm_password = False; + BOOL valid_password = False; pstring user; pstring orig_user; fstring domain; @@ -926,50 +796,16 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,int add_session_user(user); - /* - * Check with orig_user for security=server and - * security=domain. - */ - - if (!guest && !check_server_security(orig_user, domain, user, - smb_apasswd, smb_apasslen, smb_ntpasswd, smb_ntpasslen) && - !check_domain_security(orig_user, domain, user, smb_apasswd, - smb_apasslen, smb_ntpasswd, smb_ntpasslen) && - !check_hosts_equiv(user)) - { - /* - * If we get here then the user wasn't guest and the remote - * authentication methods failed. Check the authentication - * methods on this local server. - * - * If an NT password was supplied try and validate with that - * first. This is superior as the passwords are mixed case - * 128 length unicode. - */ - - if(smb_ntpasslen) - { - if(!password_ok(user, smb_ntpasswd,smb_ntpasslen)) - DEBUG(2,("NT Password did not match for user '%s'!\n", user)); - else - valid_nt_password = True; - } - - - /* check the LanMan password only if necessary and if allowed - by lp_lanman_auth() */ - if (!valid_nt_password && lp_lanman_auth()) - { - DEBUG(2,("Defaulting to Lanman password for %s\n", user)); - valid_lm_password = password_ok(user, smb_apasswd,smb_apasslen); - } - + if (!guest) { + valid_password = (pass_check_smb(user, domain, + smb_apasswd, smb_apasslen, + smb_ntpasswd, smb_ntpasslen) == NT_STATUS_NOPROBLEMO); /* The true branch will be executed if (1) the NT password failed (or was not tried), and (2) LanMan authentication failed (or was disabled) */ - if (!valid_nt_password && !valid_lm_password) + if (!valid_password) { if (lp_security() >= SEC_USER) { |