diff options
Diffstat (limited to 'source3/smbd')
-rw-r--r-- | source3/smbd/auth.c | 263 | ||||
-rw-r--r-- | source3/smbd/auth_domain.c | 2 | ||||
-rw-r--r-- | source3/smbd/auth_rhosts.c | 40 | ||||
-rw-r--r-- | source3/smbd/auth_server.c | 27 | ||||
-rw-r--r-- | source3/smbd/auth_smbpasswd.c | 228 | ||||
-rw-r--r-- | source3/smbd/auth_unix.c | 17 | ||||
-rw-r--r-- | source3/smbd/auth_util.c | 564 | ||||
-rw-r--r-- | source3/smbd/password.c | 51 | ||||
-rw-r--r-- | source3/smbd/reply.c | 37 | ||||
-rw-r--r-- | source3/smbd/service.c | 12 | ||||
-rw-r--r-- | source3/smbd/sesssetup.c | 356 |
11 files changed, 1086 insertions, 511 deletions
diff --git a/source3/smbd/auth.c b/source3/smbd/auth.c index 4bdbdf5555..4d1a566833 100644 --- a/source3/smbd/auth.c +++ b/source3/smbd/auth.c @@ -50,183 +50,160 @@ static BOOL check_domain_match(char *user, char *domain) This functions does NOT need to be in a become_root()/unbecome_root() pair as it makes the calls itself when needed. + + The return value takes precedence over the contents of the server_info + struct. When the return is other than NT_STATUS_NOPROBLEMO the contents + of that structure is undefined. + ****************************************************************************/ NTSTATUS check_password(const auth_usersupplied_info *user_info, - auth_serversupplied_info *server_info) + auth_serversupplied_info **server_info) { NTSTATUS nt_status = NT_STATUS_LOGON_FAILURE; BOOL done_pam = False; - - DEBUG(3, ("check_password: Checking password for smb user %s\\%s@%s with the new password interface\n", - user_info->smb_username.str, user_info->requested_domain.str, user_info->wksta_name.str)); - if (!check_domain_match(user_info->smb_username.str, user_info->domain.str)) { + + DEBUG(3, ("check_password: Checking password for unmapped user %s\\%s@%s with the new password interface\n", + user_info->smb_name.str, user_info->client_domain.str, user_info->wksta_name.str)); + + /* This needs to be sorted: If it doesn't match, what should we do? */ + if (!check_domain_match(user_info->smb_name.str, user_info->domain.str)) { return NT_STATUS_LOGON_FAILURE; } if (!NT_STATUS_IS_OK(nt_status)) { nt_status = check_rhosts_security(user_info, server_info); + if (NT_STATUS_IS_OK(nt_status)) { + DEBUG(7, ("check_password: Password (rhosts) for user %s suceeded\n", user_info->smb_name.str)); + } else { + DEBUG(5, ("check_password: Password (rhosts)for user %s FAILED with error %s\n", user_info->smb_name.str, get_nt_error_msg(nt_status))); + + } } if ((lp_security() == SEC_DOMAIN) && !NT_STATUS_IS_OK(nt_status)) { nt_status = check_domain_security(user_info, server_info); + if (NT_STATUS_IS_OK(nt_status)) { + DEBUG(7, ("check_password: Password (domain) for user %s suceeded\n", user_info->smb_name.str)); + } else { + DEBUG(5, ("check_password: Password (domain) for user %s FAILED with error %s\n", user_info->smb_name.str, get_nt_error_msg(nt_status))); + + } } if ((lp_security() == SEC_SERVER) && !NT_STATUS_IS_OK(nt_status)) { nt_status = check_server_security(user_info, server_info); + if (NT_STATUS_IS_OK(nt_status)) { + DEBUG(7, ("check_password: Password (server) for user %s suceeded\n", user_info->smb_name.str)); + } else { + DEBUG(5, ("check_password: Password (server) for user %s FAILED with error %s\n", user_info->smb_name.str, get_nt_error_msg(nt_status))); + + } } if (lp_security() >= SEC_SERVER) { - smb_user_control(user_info->unix_username.str, nt_status); + smb_user_control(user_info, *server_info, nt_status); } if (!NT_STATUS_IS_OK(nt_status)) { - if ((user_info->plaintext_password.len > 0) - && (!lp_plaintext_to_smbpasswd())) { + if (user_info->encrypted || lp_plaintext_to_smbpasswd()) { + nt_status = check_smbpasswd_security(user_info, server_info); + } else { 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_IS_OK(nt_status)) { + DEBUG(7, ("check_password: Password (unix/smbpasswd) for user %s suceeded\n", user_info->smb_name.str)); + } else { + DEBUG(5, ("check_password: Password (unix/smbpasswd) for user %s FAILED with error %s\n", user_info->smb_name.str, get_nt_error_msg(nt_status))); + + } } + if (NT_STATUS_IS_OK(nt_status) && !done_pam) { /* We might not be root if we are an RPC call */ become_root(); - nt_status = smb_pam_accountcheck(user_info->unix_username.str); + nt_status = smb_pam_accountcheck(pdb_get_username((*server_info)->sam_account)); unbecome_root(); - } + if (NT_STATUS_IS_OK(nt_status)) { + DEBUG(5, ("check_password: PAM Account for user %s suceeded\n", user_info->smb_name.str)); + } else { + DEBUG(3, ("check_password: PAM Account for user %s FAILED with error %s\n", user_info->smb_name.str, get_nt_error_msg(nt_status))); + + } + } + if (NT_STATUS_IS_OK(nt_status)) { - DEBUG(5, ("check_password: Password for smb user %s suceeded\n", user_info->smb_username.str)); + DEBUG(5, ("check_password: Password for smb user %s suceeded\n", user_info->smb_name.str)); } else { - DEBUG(3, ("check_password: Password for smb user %s FAILED with error %s\n", user_info->smb_username.str, get_nt_error_msg(nt_status))); - + DEBUG(3, ("check_password: Password for smb user %s FAILED with error %s\n", user_info->smb_name.str, get_nt_error_msg(nt_status))); + ZERO_STRUCTP(server_info); } + 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 + Squash an NT_STATUS return in line with requirements for unauthenticated + connections. (session setups in particular) ****************************************************************************/ -NTSTATUS pass_check_smb_with_chal(char *smb_user, char *unix_user, - char *domain, char* workstation, - uchar chal[8], - uchar *lm_pwd, int lm_pwd_len, - uchar *nt_pwd, int nt_pwd_len) +NTSTATUS nt_status_squash(NTSTATUS nt_status) { - - auth_usersupplied_info user_info; - auth_serversupplied_info server_info; - AUTH_STR ourdomain, theirdomain, unix_username, smb_username, - wksta_name; - NTSTATUS result; + if NT_STATUS_IS_OK(nt_status) { + return nt_status; + } else if NT_STATUS_EQUAL(nt_status, NT_STATUS_NO_SUCH_USER) { + /* Match WinXP and don't give the game away */ + return NT_STATUS_LOGON_FAILURE; - 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 = smb_user; - smb_username.len = strlen(smb_username.str); - - /* If unix user is NULL, use smb user */ - - unix_username.str = unix_user ? unix_user : smb_user; - unix_username.len = strlen(unix_username.str); - - user_info.unix_username = unix_username; - user_info.smb_username = smb_username; - - wksta_name.str = workstation; - wksta_name.len = strlen(workstation); - - user_info.wksta_name = wksta_name; - - memcpy(user_info.chal, chal, 8); - - if ((lm_pwd_len >= 24 || nt_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 if NT_STATUS_EQUAL(nt_status, NT_STATUS_WRONG_PASSWORD) { + /* Match WinXP and don't give the game away */ + return NT_STATUS_LOGON_FAILURE; } 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; - - - /* WATCH OUT. This doesn't work if the incoming password is incorrectly cased. - We might want to add a check here and only do an LM in that case */ + return nt_status; + } +} - /* 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 = (char *)lm_pwd; - user_info.plaintext_password.len = lm_pwd_len; - } - result = check_password(&user_info, &server_info); +/**************************************************************************** + COMPATABILITY INTERFACES: + ***************************************************************************/ - free_serversupplied_info(&server_info); /* No info needed */ +/**************************************************************************** +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 +****************************************************************************/ - return result; -} +static NTSTATUS pass_check_smb(char *smb_name, + char *domain, + DATA_BLOB lm_pwd, + DATA_BLOB nt_pwd, + DATA_BLOB plaintext_password, + BOOL encrypted) -NTSTATUS pass_check_smb(char *smb_user, char *unix_user, - char *domain, char *workstation, - 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(smb_user, unix_user, - domain, workstation, chal, - lm_pwd, lm_pwd_len, - nt_pwd, nt_pwd_len); - + NTSTATUS nt_status; + auth_usersupplied_info *user_info = NULL; + auth_serversupplied_info *server_info = NULL; + + make_user_info_for_reply(&user_info, smb_name, + domain, + lm_pwd, + nt_pwd, + plaintext_password, + encrypted); + + nt_status = check_password(user_info, &server_info); + free_user_info(&user_info); + free_server_info(&server_info); + return nt_status; } /**************************************************************************** @@ -234,36 +211,32 @@ 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 password_ok(char *smb_name, DATA_BLOB password_blob) { - extern fstring remote_machine; - /* - * 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; - } - - /* The password could be either NTLM or plain LM. Try NTLM first, but fall-through as - required. */ - if (NT_STATUS_IS_OK(pass_check_smb(user, NULL, remote_machine, lp_workgroup(), NULL, 0, (unsigned char *)password, pwlen))) { - return True; - } + DATA_BLOB null_password = data_blob(NULL, 0); + extern BOOL global_encrypted_passwords_negotiated; - if (NT_STATUS_IS_OK(pass_check_smb(user, NULL, remote_machine, lp_workgroup(), (unsigned char *)password, pwlen, NULL, 0))) { - return True; + if (global_encrypted_passwords_negotiated) { + /* + * The password could be either NTLM or plain LM. Try NTLM first, + * but fall-through as required. + * NTLMv2 makes no sense here. + */ + if (NT_STATUS_IS_OK(pass_check_smb(smb_name, lp_workgroup(), null_password, password_blob, null_password, global_encrypted_passwords_negotiated))) { + return True; + } + + if (NT_STATUS_IS_OK(pass_check_smb(smb_name, lp_workgroup(), password_blob, null_password, null_password, global_encrypted_passwords_negotiated))) { + return True; + } + } else { + if (NT_STATUS_IS_OK(pass_check_smb(smb_name, lp_workgroup(), null_password, null_password, password_blob, global_encrypted_passwords_negotiated))) { + return True; + } } return False; } -/* Free a auth_serversupplied_info structure */ -void free_serversupplied_info(auth_serversupplied_info *server_info) -{ - SAFE_FREE(server_info->group_rids); -} diff --git a/source3/smbd/auth_domain.c b/source3/smbd/auth_domain.c index bcd41bacdb..f20da19607 100644 --- a/source3/smbd/auth_domain.c +++ b/source3/smbd/auth_domain.c @@ -29,7 +29,7 @@ BOOL global_machine_password_needs_changing = False; ****************************************************************************/ NTSTATUS check_domain_security(const auth_usersupplied_info *user_info, - auth_serversupplied_info *server_info) + auth_serversupplied_info **server_info) { NTSTATUS nt_status = NT_STATUS_LOGON_FAILURE; char *p, *pserver; diff --git a/source3/smbd/auth_rhosts.c b/source3/smbd/auth_rhosts.c index 9f5f1e10e5..9c07e48a9b 100644 --- a/source3/smbd/auth_rhosts.c +++ b/source3/smbd/auth_rhosts.c @@ -131,11 +131,11 @@ static BOOL check_user_equiv(const char *user, const char *remote, const char *e /**************************************************************************** check for a possible hosts equiv or rhosts entry for the user ****************************************************************************/ -static BOOL check_hosts_equiv(char *user) /* should be const... */ + +static BOOL check_hosts_equiv(struct passwd *pass) { char *fname = NULL; pstring rhostsfile; - struct passwd *pass = Get_Pwnam(user); if (!pass) return(False); @@ -149,15 +149,15 @@ static BOOL check_hosts_equiv(char *user) /* should be const... */ } if (lp_use_rhosts()) - { - char *home = pass->pw_dir; - if (home) { - slprintf(rhostsfile, sizeof(rhostsfile)-1, "%s/.rhosts", home); - if (check_user_equiv(pass->pw_name,client_name(),rhostsfile)) - return(True); - } - } - + { + char *home = pass->pw_dir; + if (home) { + slprintf(rhostsfile, sizeof(rhostsfile)-1, "%s/.rhosts", home); + if (check_user_equiv(pass->pw_name,client_name(),rhostsfile)) + return(True); + } + } + return(False); } @@ -166,15 +166,21 @@ static BOOL check_hosts_equiv(char *user) /* should be const... */ ****************************************************************************/ NTSTATUS check_rhosts_security(const auth_usersupplied_info *user_info, - auth_serversupplied_info *server_info) + auth_serversupplied_info **server_info) { NTSTATUS nt_status = NT_STATUS_LOGON_FAILURE; - - become_root(); - if (check_hosts_equiv(user_info->unix_username.str)) { - nt_status = NT_STATUS_OK; + struct passwd *pass = Get_Pwnam(user_info->internal_username.str); + + if (pass) { + become_root(); + if (check_hosts_equiv(pass)) { + nt_status = NT_STATUS_OK; + make_server_info_pw(server_info, pass); + } + unbecome_root(); + } else { + nt_status = NT_STATUS_NO_SUCH_USER; } - unbecome_root(); return nt_status; } diff --git a/source3/smbd/auth_server.c b/source3/smbd/auth_server.c index 520417e3e0..ddbc284d50 100644 --- a/source3/smbd/auth_server.c +++ b/source3/smbd/auth_server.c @@ -115,7 +115,7 @@ struct cli_state *server_cryptkey(void) - Validate a password with the password server. ****************************************************************************/ -NTSTATUS check_server_security(const auth_usersupplied_info *user_info, auth_serversupplied_info *server_info) +NTSTATUS check_server_security(const auth_usersupplied_info *user_info, auth_serversupplied_info **server_info) { struct cli_state *cli; static unsigned char badpass[24]; @@ -134,8 +134,8 @@ NTSTATUS check_server_security(const auth_usersupplied_info *user_info, auth_ser 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))) { + if((user_info->nt_resp.length == sizeof(badpass)) && + !memcmp(badpass, user_info->nt_resp.data, sizeof(badpass))) { /* * Very unlikely, our random bad password is the same as the users * password. @@ -206,11 +206,11 @@ use this machine as the password server.\n")); * not guest enabled, we can try with the real password. */ - if (!cli_session_setup(cli, user_info->smb_username.str, - (char *)user_info->lm_resp.buffer, - user_info->lm_resp.len, - (char *)user_info->nt_resp.buffer, - user_info->nt_resp.len, + if (!cli_session_setup(cli, user_info->smb_name.str, + (char *)user_info->lm_resp.data, + user_info->lm_resp.length, + (char *)user_info->nt_resp.data, + user_info->nt_resp.length, user_info->domain.str)) { DEBUG(1,("password server %s rejected the password\n", cli->desthost)); /* Make this cli_nt_error() when the conversion is in */ @@ -227,5 +227,16 @@ use this machine as the password server.\n")); cli_ulogoff(cli); + if NT_STATUS_IS_OK(nt_status) { + struct passwd *pass = Get_Pwnam(user_info->internal_username.str); + if (pass) { + if (!make_server_info_pw(server_info, pass)) { + nt_status = NT_STATUS_NO_MEMORY; + } + } else { + nt_status = NT_STATUS_NO_SUCH_USER; + } + } + return(nt_status); } diff --git a/source3/smbd/auth_smbpasswd.c b/source3/smbd/auth_smbpasswd.c index 84ca8d03be..d4283429ce 100644 --- a/source3/smbd/auth_smbpasswd.c +++ b/source3/smbd/auth_smbpasswd.c @@ -26,53 +26,65 @@ /**************************************************************************** core of smb password checking routine. ****************************************************************************/ -static BOOL smb_pwd_check_ntlmv1(const uchar *password, +static BOOL smb_pwd_check_ntlmv1(DATA_BLOB nt_response, const uchar *part_passwd, - const uchar *c8, - char user_sess_key[16]) + DATA_BLOB sec_blob, + uint8 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; - } + /* 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; + } + + if (sec_blob.length != 8) { + DEBUG(0, ("smb_pwd_check_ntlmv1: incorrect challange size (%d)\n", sec_blob.length)); + return False; + } + + if (nt_response.length != 24) { + DEBUG(0, ("smb_pwd_check_ntlmv1: incorrect password length (%d)\n", nt_response.length)); + return False; + } - SMBOWFencrypt(part_passwd, c8, p24); + SMBOWFencrypt(part_passwd, sec_blob.data, 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); + dump_data(100, nt_response.data, nt_response.length); DEBUG(100,("Given challenge was |")); - dump_data(100, c8, 8); + dump_data(100, sec_blob.data, sec_blob.length); DEBUG(100,("Value from encryption was |")); dump_data(100, p24, 24); #endif - return (memcmp(p24, password, 24) == 0); + return (memcmp(p24, nt_response.data, 24) == 0); } /**************************************************************************** core of smb password checking routine. ****************************************************************************/ -static BOOL smb_pwd_check_ntlmv2(const uchar *password, size_t pwd_len, +static BOOL smb_pwd_check_ntlmv2(const DATA_BLOB ntv2_response, const uchar *part_passwd, - const uchar *c8, + const DATA_BLOB sec_blob, const char *user, const char *domain, - char user_sess_key[16]) + uint8 user_sess_key[16]) { /* Finish the encryption of part_passwd. */ uchar kr[16]; - uchar resp[16]; + uchar value_from_encryption[16]; + uchar client_response[16]; + DATA_BLOB client_key_data; if (part_passwd == NULL) { @@ -81,25 +93,42 @@ static BOOL smb_pwd_check_ntlmv2(const uchar *password, size_t pwd_len, return False; } + if (ntv2_response.length < 16) { + /* We MUST have more than 16 bytes, or the stuff below will go + crazy... */ + DEBUG(0, ("smb_pwd_check_ntlmv1: incorrect password length (%d)\n", + ntv2_response.length)); + return False; + } + + client_key_data = data_blob(ntv2_response.data+16, ntv2_response.length-16); + memcpy(client_response, ntv2_response.data, ntv2_response.length); + + if (!client_key_data.data) { + return False; + } + ntv2_owf_gen(part_passwd, user, domain, kr); - SMBOWFencrypt_ntv2(kr, c8, 8, password+16, pwd_len-16, (char *)resp); + SMBOWFencrypt_ntv2(kr, sec_blob, client_key_data, (char *)value_from_encryption); if (user_sess_key != NULL) { - SMBsesskeygen_ntv2(kr, resp, user_sess_key); + SMBsesskeygen_ntv2(kr, value_from_encryption, 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); + dump_data(100, ntv2_response.data, ntv2_response.length); + DEBUG(100,("Variable data from client was |")); + dump_data(100, ntv2_response.data, ntv2_response.length); DEBUG(100,("Given challenge was |")); - dump_data(100, c8, 8); + dump_data(100, sec_blob.data, sec_blob.length); DEBUG(100,("Value from encryption was |")); - dump_data(100, resp, 16); + dump_data(100, value_from_encryption, 16); #endif - - return (memcmp(resp, password, 16) == 0); + data_blob_clear_free(&client_key_data); + return (memcmp(value_from_encryption, client_response, 16) == 0); } @@ -107,11 +136,12 @@ static BOOL smb_pwd_check_ntlmv2(const uchar *password, size_t pwd_len, Do a specific test for an smb password being correct, given a smb_password and the lanman and NT responses. ****************************************************************************/ -NTSTATUS sam_password_ok(SAM_ACCOUNT *sampass, const auth_usersupplied_info *user_info, char user_sess_key[16]) +NTSTATUS sam_password_ok(SAM_ACCOUNT *sampass, const auth_usersupplied_info *user_info, uint8 user_sess_key[16]) { const uint8 *nt_pw, *lm_pw; uint16 acct_ctrl = pdb_get_acct_ctrl(sampass); - + uint32 ntlmssp_flags; + if (!user_info || !sampass) return NT_STATUS_LOGON_FAILURE; @@ -119,12 +149,12 @@ NTSTATUS sam_password_ok(SAM_ACCOUNT *sampass, const auth_usersupplied_info *use { if (lp_null_passwords()) { - DEBUG(3,("Account for user '%s' has no password and null passwords are allowed.\n", sampass->username)); + DEBUG(3,("Account for user '%s' has no password and null passwords are allowed.\n", pdb_get_username(sampass))); return(NT_STATUS_OK); } else { - DEBUG(3,("Account for user '%s' has no password and null passwords are NOT allowed.\n", sampass->username)); + DEBUG(3,("Account for user '%s' has no password and null passwords are NOT allowed.\n", pdb_get_username(sampass))); return(NT_STATUS_LOGON_FAILURE); } } @@ -132,61 +162,84 @@ NTSTATUS sam_password_ok(SAM_ACCOUNT *sampass, const auth_usersupplied_info *use nt_pw = pdb_get_nt_passwd(sampass); lm_pw = pdb_get_lanman_passwd(sampass); - if (nt_pw != NULL && user_info->nt_resp.len > 0) { - if ((user_info->nt_resp.len > 24 )) { + ntlmssp_flags = user_info->ntlmssp_flags; + + if (nt_pw == NULL) { + DEBUG(3,("smb_password_ok: NO NT password stored for user %s.\n", + pdb_get_username(sampass))); + /* No return, we want to check the LM hash below in this case */ + ntlmssp_flags &= (~(NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_NTLM2)); + } + + if (ntlmssp_flags & NTLMSSP_NEGOTIATE_NTLM2) { /* 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, + if (smb_pwd_check_ntlmv2( user_info->nt_resp, nt_pw, - user_info->chal, user_info->smb_username.str, - user_info->requested_domain.str, + user_info->sec_blob, user_info->smb_name.str, + user_info->client_domain.str, user_sess_key)) { return NT_STATUS_OK; } else { - DEBUG(4,("smb_password_ok: NTLMv2 password check failed\n")); - return NT_STATUS_WRONG_PASSWORD; + DEBUG(3,("smb_password_ok: NTLMv2 password check failed\n")); + return NT_STATUS_WRONG_PASSWORD; } - - } else if (lp_ntlm_auth() && (user_info->nt_resp.len == 24)) { + } else if (ntlmssp_flags & NTLMSSP_NEGOTIATE_NTLM) { + if (lp_ntlm_auth()) { /* 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, - user_sess_key)) - { - return NT_STATUS_OK; + DEBUG(4,("smb_password_ok: Checking NT MD4 password\n")); + if (smb_pwd_check_ntlmv1(user_info->nt_resp, + nt_pw, user_info->sec_blob, + user_sess_key)) + { + return NT_STATUS_OK; + } else { + DEBUG(3,("smb_password_ok: NT MD4 password check failed for user %s\n",pdb_get_username(sampass))); + return NT_STATUS_WRONG_PASSWORD; + } } else { - DEBUG(4,("smb_password_ok: NT MD4 password check failed\n")); - return NT_STATUS_WRONG_PASSWORD; + DEBUG(2,("smb_password_ok: NTLMv1 passwords NOT PERMITTED for user %s\n",pdb_get_username(sampass))); + /* No return, we want to check the LM hash below in this case */ } - } else { - return NT_STATUS_LOGON_FAILURE; - } } - if (lm_pw != NULL && user_info->lm_resp.len == 24) { - if (lp_lanman_auth()) { - DEBUG(4,("smb_password_ok: Checking LM password\n")); - if (smb_pwd_check_ntlmv1(user_info->lm_resp.buffer, - lm_pw, user_info->chal, - user_sess_key)) - { - return NT_STATUS_OK; - } else { - DEBUG(4,("smb_password_ok: LM password check failed\n")); - return NT_STATUS_WRONG_PASSWORD; - } + if (lm_pw == NULL) { + DEBUG(3,("smb_password_ok: NO LanMan password set for user %s (and no NT password supplied)\n",pdb_get_username(sampass))); + ntlmssp_flags &= (~NTLMSSP_NEGOTIATE_OEM); + } + + if (ntlmssp_flags & NTLMSSP_NEGOTIATE_OEM) { + + if (user_info->lm_resp.length != 24) { + DEBUG(2,("smb_password_ok: invalid LanMan password length (%d) for user %s\n", + user_info->nt_resp.length, pdb_get_username(sampass))); } + + if (!lp_lanman_auth()) { + DEBUG(3,("smb_password_ok: Lanman passwords NOT PERMITTED for user %s\n",pdb_get_username(sampass))); + return NT_STATUS_LOGON_FAILURE; + } + + DEBUG(4,("smb_password_ok: Checking LM password\n")); + if (smb_pwd_check_ntlmv1(user_info->lm_resp, + lm_pw, user_info->sec_blob, + user_sess_key)) + { + return NT_STATUS_OK; + } else { + DEBUG(4,("smb_password_ok: LM password check failed for user %s\n",pdb_get_username(sampass))); + return NT_STATUS_WRONG_PASSWORD; + } } - /* Should not be reached */ - return NT_STATUS_LOGON_FAILURE; + /* Should not be reached, but if they send nothing... */ + DEBUG(3,("smb_password_ok: NEITHER LanMan nor NT password supplied for user %s\n",pdb_get_username(sampass))); + return NT_STATUS_WRONG_PASSWORD; } /**************************************************************************** @@ -290,33 +343,58 @@ SMB hash supplied in the user_info structure return an NT_STATUS constant. ****************************************************************************/ -NTSTATUS check_smbpasswd_security(const auth_usersupplied_info *user_info, auth_serversupplied_info *server_info) +NTSTATUS check_smbpasswd_security(const auth_usersupplied_info *user_info, auth_serversupplied_info **server_info) { SAM_ACCOUNT *sampass=NULL; BOOL ret; NTSTATUS nt_status; + uint8 user_sess_key[16]; + const uint8* lm_hash; pdb_init_sam(&sampass); /* get the account information */ become_root(); - ret = pdb_getsampwnam(sampass, user_info->unix_username.str); + ret = pdb_getsampwnam(sampass, user_info->internal_username.str); unbecome_root(); if (ret == False) { - DEBUG(1,("Couldn't find user '%s' in passdb file.\n", user_info->unix_username.str)); + DEBUG(1,("Couldn't find user '%s' in passdb file.\n", user_info->internal_username.str)); pdb_free_sam(&sampass); return NT_STATUS_NO_SUCH_USER; } - nt_status = sam_password_ok(sampass, user_info, (char *)(server_info->session_key)); + nt_status = sam_password_ok(sampass, user_info, user_sess_key); - if NT_STATUS_IS_OK(nt_status) { - nt_status = sam_account_ok(sampass, user_info); + if (!NT_STATUS_IS_OK(nt_status)) { + pdb_free_sam(&sampass); + return nt_status; } - pdb_free_sam(&sampass); + nt_status = sam_account_ok(sampass, user_info); + + if (!NT_STATUS_IS_OK(nt_status)) { + pdb_free_sam(&sampass); + return nt_status; + } + + if (!make_server_info_sam(server_info, sampass)) { + DEBUG(0,("failed to malloc memory for server_info\n")); + return NT_STATUS_NO_MEMORY; + } + + lm_hash = pdb_get_lanman_passwd((*server_info)->sam_account); + if (lm_hash) { + memcpy((*server_info)->first_8_lm_hash, lm_hash, 8); + } + + memcpy((*server_info)->session_key, user_sess_key, sizeof(user_sess_key)); + return nt_status; } + + + + diff --git a/source3/smbd/auth_unix.c b/source3/smbd/auth_unix.c index 29a2a6eafb..d456da1fdf 100644 --- a/source3/smbd/auth_unix.c +++ b/source3/smbd/auth_unix.c @@ -82,22 +82,27 @@ check if a username/password is OK assuming the password in PLAIN TEXT ****************************************************************************/ -NTSTATUS check_unix_security(const auth_usersupplied_info *user_info, auth_serversupplied_info *server_info) +NTSTATUS check_unix_security(const auth_usersupplied_info *user_info, auth_serversupplied_info **server_info) { NTSTATUS nt_status; struct passwd *pass = NULL; become_root(); - - pass = Get_Pwnam(user_info->unix_username.str); + pass = Get_Pwnam(user_info->internal_username.str); nt_status = pass_check(pass, - pass ? pass->pw_name : user_info->unix_username.str, - user_info->plaintext_password.str, - user_info->plaintext_password.len, + pass ? pass->pw_name : user_info->internal_username.str, + (char *)user_info->plaintext_password.data, + user_info->plaintext_password.length-1, lp_update_encrypted() ? update_smbpassword_file : NULL, True); + + if NT_STATUS_IS_OK(nt_status) { + if (pass) { + make_server_info_pw(server_info, pass); + } + } unbecome_root(); diff --git a/source3/smbd/auth_util.c b/source3/smbd/auth_util.c index d3b9aa7001..297c482af5 100644 --- a/source3/smbd/auth_util.c +++ b/source3/smbd/auth_util.c @@ -25,6 +25,8 @@ /* Data to do lanman1/2 password challenge. */ static unsigned char saved_challenge[8]; static BOOL challenge_sent=False; +extern fstring remote_machine; +extern pstring global_myname; /******************************************************************* Get the next challenge value - no repeats. @@ -64,7 +66,7 @@ BOOL last_challenge(unsigned char *challenge) Create a UNIX user on demand. ****************************************************************************/ -static int smb_create_user(char *unix_user, char *homedir) +static int smb_create_user(const char *unix_user, const char *homedir) { pstring add_script; int ret; @@ -100,40 +102,560 @@ static int smb_delete_user(char *unix_user) Add and Delete UNIX users on demand, based on NTSTATUS codes. ****************************************************************************/ -void smb_user_control(char *unix_user, NTSTATUS nt_status) +void smb_user_control(const auth_usersupplied_info *user_info, auth_serversupplied_info *server_info, NTSTATUS nt_status) { struct passwd *pwd=NULL; if (NT_STATUS_IS_OK(nt_status)) { - /* - * 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; + if (!(server_info->sam_fill_level & SAM_FILL_UNIX)) { + /* - * 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. + * 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 = Get_Pwnam(user_info->internal_username.str))) { + smb_create_user(user_info->internal_username.str, NULL); + } + } else { + if(lp_adduser_script()) { + SMB_STRUCT_STAT st; + const char *home_dir = pdb_get_homedir(server_info->sam_account); + /* + * 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); + if (home_dir && + (sys_stat(home_dir, &st) == -1) && (errno == ENOENT)) { + smb_create_user(user_info->internal_username.str, home_dir); + } + } } - - } else if (NT_STATUS_V(nt_status) == NT_STATUS_V(NT_STATUS_NO_SUCH_USER)) { + } else if (NT_STATUS_EQUAL(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); + if (lp_deluser_script()) { + smb_delete_user(user_info->internal_username.str); + } + } +} + +/**************************************************************************** + Create an auth_usersupplied_data structure +****************************************************************************/ + +BOOL make_user_info(auth_usersupplied_info **user_info, + char *smb_name, char *internal_username, + char *client_domain, char *domain, + char *wksta_name, DATA_BLOB sec_blob, + DATA_BLOB lm_pwd, DATA_BLOB nt_pwd, + DATA_BLOB plaintext, + uint32 ntlmssp_flags, BOOL encrypted) +{ + + DEBUG(5,("attempting to make a user_info for %s (%s)\n", internal_username, smb_name)); + + *user_info = malloc(sizeof(**user_info)); + if (!user_info) { + DEBUG(0,("malloc failed for user_info (size %d)\n", sizeof(*user_info))); + return False; + } + + ZERO_STRUCTP(*user_info); + + DEBUG(5,("makeing strings for %s's user_info struct\n", internal_username)); + + (*user_info)->smb_name.str = strdup(smb_name); + if ((*user_info)->smb_name.str) { + (*user_info)->smb_name.len = strlen(smb_name); + } else { + free_user_info(user_info); + return False; + } + + (*user_info)->internal_username.str = strdup(internal_username); + if ((*user_info)->internal_username.str) { + (*user_info)->internal_username.len = strlen(internal_username); + } else { + free_user_info(user_info); + return False; + } + + (*user_info)->domain.str = strdup(domain); + if ((*user_info)->domain.str) { + (*user_info)->domain.len = strlen(domain); + } else { + free_user_info(user_info); + return False; + } + + (*user_info)->client_domain.str = strdup(client_domain); + if ((*user_info)->client_domain.str) { + (*user_info)->client_domain.len = strlen(client_domain); + } else { + free_user_info(user_info); + return False; + } + + (*user_info)->wksta_name.str = strdup(wksta_name); + if ((*user_info)->wksta_name.str) { + (*user_info)->wksta_name.len = strlen(wksta_name); + } else { + free_user_info(user_info); + return False; } + + DEBUG(5,("makeing blobs for %s's user_info struct\n", internal_username)); + + (*user_info)->sec_blob = data_blob(sec_blob.data, sec_blob.length); + (*user_info)->lm_resp = data_blob(lm_pwd.data, lm_pwd.length); + (*user_info)->nt_resp = data_blob(nt_pwd.data, nt_pwd.length); + (*user_info)->plaintext_password = data_blob(plaintext.data, plaintext.length); + + (*user_info)->encrypted = encrypted; + (*user_info)->ntlmssp_flags = ntlmssp_flags; + + DEBUG(10,("made an %sencrypted user_info for %s (%s)\n", encrypted ? "":"un" , internal_username, smb_name)); + + return True; } + +/**************************************************************************** + Create an auth_usersupplied_data structure after appropriate mapping. +****************************************************************************/ + +BOOL make_user_info_map(auth_usersupplied_info **user_info, + char *smb_name, + char *client_domain, + char *wksta_name, DATA_BLOB sec_blob, + DATA_BLOB lm_pwd, DATA_BLOB nt_pwd, + DATA_BLOB plaintext, + uint32 ntlmssp_flags, BOOL encrypted) +{ + char *domain; + fstring internal_username; + fstrcpy(internal_username, smb_name); + map_username(internal_username); + + if (lp_allow_trusted_domains()) { + domain = client_domain; + } else { + domain = lp_workgroup(); + } + + return make_user_info(user_info, + smb_name, internal_username, + client_domain, domain, + wksta_name, sec_blob, + lm_pwd, nt_pwd, + plaintext, + ntlmssp_flags, encrypted); + +} + +/**************************************************************************** + Create an auth_usersupplied_data, making the DATA_BLOBs here. + Decrupt and encrypt the passwords. +****************************************************************************/ + +BOOL make_user_info_netlogon_network(auth_usersupplied_info **user_info, + char *smb_name, + char *client_domain, + char *wksta_name, uchar chal[8], + uchar *lm_network_pwd, int lm_pwd_len, + uchar *nt_network_pwd, int nt_pwd_len) +{ + BOOL ret; + DATA_BLOB sec_blob = data_blob(chal, sizeof(chal)); + DATA_BLOB lm_blob = data_blob(lm_network_pwd, lm_pwd_len); + DATA_BLOB nt_blob = data_blob(nt_network_pwd, nt_pwd_len); + DATA_BLOB plaintext_blob = data_blob(NULL, 0); + uint32 ntlmssp_flags = 0; + + if (lm_pwd_len) + ntlmssp_flags |= NTLMSSP_NEGOTIATE_OEM; + if (nt_pwd_len) + ntlmssp_flags |= NTLMSSP_NEGOTIATE_NTLM; + + ret = make_user_info_map(user_info, + smb_name, client_domain, + wksta_name, sec_blob, + nt_blob, lm_blob, + plaintext_blob, + ntlmssp_flags, True); + + data_blob_free(&lm_blob); + data_blob_free(&nt_blob); + return ret; +} + +/**************************************************************************** + Create an auth_usersupplied_data, making the DATA_BLOBs here. + Decrupt and encrypt the passwords. +****************************************************************************/ + +BOOL make_user_info_netlogon_interactive(auth_usersupplied_info **user_info, + char *smb_name, + char *client_domain, + char *wksta_name, + uchar *lm_interactive_pwd, int lm_pwd_len, + uchar *nt_interactive_pwd, int nt_pwd_len, + uchar *dc_sess_key) +{ + char nt_pwd[16]; + char lm_pwd[16]; + unsigned char local_lm_response[24]; + unsigned char local_nt_response[24]; + unsigned char key[16]; + uint8 chal[8]; + uint32 ntlmssp_flags = 0; + + generate_random_buffer(chal, 8, False); + + memset(key, 0, 16); + memcpy(key, dc_sess_key, 8); + + memcpy(lm_pwd, lm_interactive_pwd, 16); + memcpy(nt_pwd, nt_interactive_pwd, 16); + +#ifdef DEBUG_PASSWORD + DEBUG(100,("key:")); + dump_data(100, (char *)key, 16); + + DEBUG(100,("lm owf password:")); + dump_data(100, lm_pwd, 16); + + DEBUG(100,("nt owf password:")); + dump_data(100, nt_pwd, 16); +#endif + + SamOEMhash((uchar *)lm_pwd, key, 16); + SamOEMhash((uchar *)nt_pwd, key, 16); + +#ifdef DEBUG_PASSWORD + DEBUG(100,("decrypt of lm owf password:")); + dump_data(100, lm_pwd, 16); + + DEBUG(100,("decrypt of nt owf password:")); + dump_data(100, nt_pwd, 16); +#endif + + generate_random_buffer(chal, 8, False); + SMBOWFencrypt((const unsigned char *)lm_pwd, chal, local_lm_response); + SMBOWFencrypt((const unsigned char *)nt_pwd, chal, local_nt_response); + + /* Password info parinoia */ + ZERO_STRUCT(lm_pwd); + ZERO_STRUCT(nt_pwd); + ZERO_STRUCT(key); + + { + BOOL ret; + DATA_BLOB sec_blob = data_blob(chal, sizeof(chal)); + DATA_BLOB local_lm_blob = data_blob(local_lm_response, sizeof(local_lm_response)); + DATA_BLOB local_nt_blob = data_blob(local_nt_response, sizeof(local_nt_response)); + DATA_BLOB plaintext_blob = data_blob(NULL, 0); + + ntlmssp_flags = NTLMSSP_NEGOTIATE_OEM | NTLMSSP_NEGOTIATE_NTLM; + ret = make_user_info_map(user_info, + smb_name, client_domain, + wksta_name, sec_blob, + local_nt_blob, + local_lm_blob, + plaintext_blob, + ntlmssp_flags, True); + + data_blob_free(&local_lm_blob); + data_blob_free(&local_nt_blob); + return ret; + } +} + +/**************************************************************************** + Create an auth_usersupplied_data structure +****************************************************************************/ + +BOOL make_user_info_for_winbind(auth_usersupplied_info **user_info, + char *username, + char *domain, + char *password) +{ + unsigned char local_lm_response[24]; + unsigned char local_nt_response[24]; + char chal[8]; + DATA_BLOB local_lm_blob; + DATA_BLOB local_nt_blob; + DATA_BLOB plaintext_blob; + uint32 ntlmssp_flags = 0; + + /* + * Not encrypted - do so. + */ + + DEBUG(5,("pass_check_smb: User passwords not in encrypted format.\n")); + + generate_random_buffer(chal, 8, False); + + if (*password) { + SMBencrypt( (uchar *)password, chal, local_lm_response); + + /* This encrypts the lm_pwd feild, which actualy contains the password + rather than the nt_pwd field becouse that contains nothing */ + + /* WATCH OUT. This doesn't work if the incoming password is incorrectly cased. + We might want to add a check here and only do an LM in that case */ + + SMBNTencrypt((uchar *)password, chal, local_nt_response); + + local_lm_blob = data_blob(local_lm_response, sizeof(local_lm_response)); + local_nt_blob = data_blob(local_nt_response, sizeof(local_nt_response)); + plaintext_blob = data_blob(password, strlen(password)+1); + if ((!local_lm_blob.data) || (!local_nt_blob.data)|| (!plaintext_blob.data)) { + data_blob_free(&local_lm_blob); + data_blob_free(&local_nt_blob); + data_blob_clear_free(&plaintext_blob); + return False; + } + ntlmssp_flags = NTLMSSP_NEGOTIATE_OEM | NTLMSSP_NEGOTIATE_NTLM; + } else { + local_lm_blob = data_blob(NULL, 0); + local_nt_blob = data_blob(NULL, 0); + plaintext_blob = data_blob(NULL, 0); + } + + { + BOOL ret; + DATA_BLOB sec_blob = data_blob(chal, sizeof(chal)); + + if (!sec_blob.data) { + return False; + } + + ret = make_user_info(user_info, + username, username, + domain, domain, + global_myname, sec_blob, + local_nt_blob, + local_lm_blob, + plaintext_blob, + ntlmssp_flags, False); + + data_blob_free(&local_lm_blob); + data_blob_free(&local_nt_blob); + data_blob_clear_free(&plaintext_blob); + return ret; + } +} + +/**************************************************************************** + Create an auth_usersupplied_data, making the DATA_BLOBs here. + Decrupt and encrypt the passwords. +****************************************************************************/ + +BOOL make_user_info_winbind_crap(auth_usersupplied_info **user_info, + char *smb_name, + char *client_domain, + uchar chal[8], + uchar *lm_network_pwd, int lm_pwd_len, + uchar *nt_network_pwd, int nt_pwd_len) +{ + BOOL ret; + DATA_BLOB sec_blob = data_blob(chal, sizeof(chal)); + DATA_BLOB lm_blob = data_blob(lm_network_pwd, lm_pwd_len); + DATA_BLOB nt_blob = data_blob(nt_network_pwd, nt_pwd_len); + DATA_BLOB plaintext_blob = data_blob(NULL, 0); + uint32 ntlmssp_flags = 0; + + if (lm_pwd_len) + ntlmssp_flags |= NTLMSSP_NEGOTIATE_OEM; + if (nt_pwd_len) + ntlmssp_flags |= NTLMSSP_NEGOTIATE_NTLM; + + ret = make_user_info(user_info, + smb_name, smb_name, + client_domain, client_domain, + global_myname, sec_blob, + nt_blob, lm_blob, + plaintext_blob, + ntlmssp_flags, True); + + data_blob_free(&lm_blob); + data_blob_free(&nt_blob); + return ret; +} + +/**************************************************************************** + Create an auth_usersupplied_data structure +****************************************************************************/ + +BOOL make_user_info_for_reply(auth_usersupplied_info **user_info, + char *smb_name, + char *client_domain, + DATA_BLOB lm_resp, DATA_BLOB nt_resp, + DATA_BLOB plaintext_password, + BOOL encrypted) +{ + uchar chal[8]; + + DATA_BLOB local_lm_blob; + DATA_BLOB local_nt_blob; + DATA_BLOB sec_blob; + BOOL ret = False; + uint32 ntlmssp_flags = 0; + + if (encrypted) { + DATA_BLOB no_plaintext_blob = data_blob(NULL, 0); + if (!last_challenge(chal)) { + DEBUG(0,("Encrypted login but no challange set!\n")); + return False; + } + sec_blob = data_blob(chal, 8); + + if (lm_resp.length == 24) { + ntlmssp_flags |= NTLMSSP_NEGOTIATE_OEM; + } + if (nt_resp.length == 0) { + } else if (nt_resp.length == 24) { + ntlmssp_flags |= NTLMSSP_NEGOTIATE_NTLM; + } else { + ntlmssp_flags |= NTLMSSP_NEGOTIATE_NTLM2; + } + + return make_user_info_map(user_info, smb_name, + client_domain, + remote_machine, sec_blob, + lm_resp, + nt_resp, + no_plaintext_blob, + ntlmssp_flags, encrypted); + } + + generate_random_buffer(chal, 8, False); + + sec_blob = data_blob(chal, 8); + + /* + * Not encrypted - do so. + */ + + DEBUG(5,("pass_check_smb: User passwords not in encrypted format.\n")); + + if (plaintext_password.data) { + unsigned char local_lm_response[24]; + + SMBencrypt( (uchar *)plaintext_password.data, chal, local_lm_response); + local_lm_blob = data_blob(local_lm_response, 24); + + /* We can't do an NT hash here, as the password needs to be case insensitive */ + local_nt_blob = data_blob(NULL, 0); + + ntlmssp_flags = NTLMSSP_NEGOTIATE_OEM; + } else { + local_lm_blob = data_blob(NULL, 0); + local_nt_blob = data_blob(NULL, 0); + } + + ret = make_user_info_map(user_info, smb_name, + client_domain, + remote_machine, + sec_blob, + local_lm_blob, + local_nt_blob, + plaintext_password, + ntlmssp_flags, encrypted); + + data_blob_free(&local_lm_blob); + return ret; +} + +BOOL make_server_info(auth_serversupplied_info **server_info) +{ + *server_info = malloc(sizeof(**server_info)); + if (!*server_info) { + DEBUG(0,("make_server_info_sam: malloc failed!\n")); + return False; + } + ZERO_STRUCTP(*server_info); + return True; +} + +BOOL make_server_info_sam(auth_serversupplied_info **server_info, SAM_ACCOUNT *sampass) +{ + if (!make_server_info(server_info)) { + return False; + } + + (*server_info)->sam_fill_level = SAM_FILL_ALL; + (*server_info)->sam_account = sampass; + + DEBUG(5,("make_server_info_sam: made sever info for user %s\n", + pdb_get_username((*server_info)->sam_account))); + return True; +} + +BOOL make_server_info_pw(auth_serversupplied_info **server_info, struct passwd *pwd) +{ + SAM_ACCOUNT *sampass = NULL; + if (!pdb_init_sam_pw(&sampass, pwd)) { + return False; + } + return make_server_info_sam(server_info, sampass); +} + +void free_user_info(auth_usersupplied_info **user_info) +{ + DEBUG(5,("attempting to free (and zero) a user_info structure\n")); + if (*user_info != NULL) { + if ((*user_info)->smb_name.str) { + DEBUG(10,("structure was created for %s\n", (*user_info)->smb_name.str)); + } + SAFE_FREE((*user_info)->smb_name.str); + SAFE_FREE((*user_info)->internal_username.str); + SAFE_FREE((*user_info)->client_domain.str); + SAFE_FREE((*user_info)->domain.str); + data_blob_free(&(*user_info)->sec_blob); + data_blob_free(&(*user_info)->lm_resp); + data_blob_free(&(*user_info)->nt_resp); + SAFE_FREE((*user_info)->interactive_password); + data_blob_clear_free(&(*user_info)->plaintext_password); + ZERO_STRUCT(**user_info); + } + SAFE_FREE(*user_info); +} + +/*************************************************************************** + Clear out a server_info struct that has been allocated +***************************************************************************/ +void free_server_info(auth_serversupplied_info **server_info) +{ + if (*server_info != NULL) { + pdb_free_sam(&(*server_info)->sam_account); + + /* call pam_end here, unless we know we are keeping it */ + SAFE_FREE((*server_info)->group_rids); + + ZERO_STRUCT(**server_info); + } + SAFE_FREE(*server_info); +} + +/*************************************************************************** + Make a server_info struct for a guest user +***************************************************************************/ +void make_server_info_guest(auth_serversupplied_info **server_info) +{ + struct passwd *pass = sys_getpwnam(lp_guestaccount(-1)); + + if (pass) { + make_server_info_pw(server_info, pass); + } +} + diff --git a/source3/smbd/password.c b/source3/smbd/password.c index e8f40f1fa3..01eabfda5e 100644 --- a/source3/smbd/password.c +++ b/source3/smbd/password.c @@ -197,10 +197,11 @@ has been given. vuid is biased by an offset. This allows us to tell random client vuid's (normally zero) from valid vuids. ****************************************************************************/ -int register_vuid(uid_t uid,gid_t gid, char *unix_name, char *requested_name, - char *domain,BOOL guest, char *full_name) +int register_vuid(auth_serversupplied_info *server_info, char *smb_name, BOOL guest) { user_struct *vuser = NULL; + uid_t *puid; + gid_t *pgid; /* Ensure no vuid gets registered in share level security. */ if(lp_security() == SEC_SHARE) @@ -217,8 +218,14 @@ int register_vuid(uid_t uid,gid_t gid, char *unix_name, char *requested_name, ZERO_STRUCTP(vuser); - DEBUG(10,("register_vuid: (%u,%u) %s %s %s guest=%d\n", (unsigned int)uid, (unsigned int)gid, - unix_name, requested_name, domain, guest )); + puid = pdb_get_uid(server_info->sam_account); + pgid = pdb_get_gid(server_info->sam_account); + + if (!puid || !pgid) { + DEBUG(0,("Attempted session setup with invalid user. No uid/gid in SAM_ACCOUNT\n")); + free(vuser); + return UID_FIELD_INVALID; + } /* Allocate a free vuid. Yes this is a linear search... :-) */ while( get_valid_user_struct(next_vuid) != NULL ) { @@ -231,13 +238,19 @@ int register_vuid(uid_t uid,gid_t gid, char *unix_name, char *requested_name, DEBUG(10,("register_vuid: allocated vuid = %u\n", (unsigned int)next_vuid )); vuser->vuid = next_vuid; - vuser->uid = uid; - vuser->gid = gid; + vuser->uid = *puid; + vuser->gid = *pgid; vuser->guest = guest; - fstrcpy(vuser->user.unix_name,unix_name); - fstrcpy(vuser->user.smb_name,requested_name); - fstrcpy(vuser->user.domain,domain); - fstrcpy(vuser->user.full_name, full_name); + fstrcpy(vuser->user.unix_name, pdb_get_username(server_info->sam_account)); + fstrcpy(vuser->user.smb_name, smb_name); + fstrcpy(vuser->user.domain, pdb_get_domain(server_info->sam_account)); + fstrcpy(vuser->user.full_name, pdb_get_fullname(server_info->sam_account)); + + DEBUG(10,("register_vuid: (%u,%u) %s %s %s guest=%d\n", + (unsigned int)vuser->uid, + (unsigned int)vuser->gid, + vuser->user.unix_name, vuser->user.smb_name, vuser->user.domain, guest )); + DEBUG(3, ("User name: %s\tReal name: %s\n",vuser->user.unix_name,vuser->user.full_name)); vuser->n_groups = 0; @@ -332,7 +345,7 @@ BOOL user_ok(char *user,int snum) /**************************************************************************** validate a group username entry. Return the username or NULL ****************************************************************************/ -static char *validate_group(char *group,char *password,int pwlen,int snum) +static char *validate_group(char *group, DATA_BLOB password,int snum) { #ifdef HAVE_NETGROUP { @@ -341,7 +354,7 @@ static char *validate_group(char *group,char *password,int pwlen,int snum) while (getnetgrent(&host, &user, &domain)) { if (user) { if (user_ok(user, snum) && - password_ok(user,password,pwlen)) { + password_ok(user,password)) { endnetgrent(); return(user); } @@ -396,7 +409,7 @@ static char *validate_group(char *group,char *password,int pwlen,int snum) static fstring name; fstrcpy(name,member); if (user_ok(name,snum) && - password_ok(name,password,pwlen)) { + password_ok(name,password)) { endgrent(); return(&name[0]); } @@ -419,7 +432,7 @@ static char *validate_group(char *group,char *password,int pwlen,int snum) Note this is *NOT* used when logging on using sessionsetup_and_X. ****************************************************************************/ -BOOL authorise_login(int snum,char *user,char *password, int pwlen, +BOOL authorise_login(int snum,char *user, DATA_BLOB password, BOOL *guest,BOOL *force,uint16 vuid) { BOOL ok = False; @@ -427,7 +440,7 @@ BOOL authorise_login(int snum,char *user,char *password, int pwlen, #if DEBUG_PASSWORD DEBUG(100,("authorise_login: checking authorisation on user=%s pass=%s\n", - user,password)); + user,password.data)); #endif *guest = False; @@ -472,7 +485,7 @@ BOOL authorise_login(int snum,char *user,char *password, int pwlen, /* check for a previously registered guest username */ if (!ok && (vuser != 0) && vuser->guest) { if (user_ok(vuser->user.unix_name,snum) && - password_ok(vuser->user.unix_name, password, pwlen)) { + password_ok(vuser->user.unix_name, password)) { fstrcpy(user, vuser->user.unix_name); vuser->guest = False; DEBUG(3,("authorise_login: ACCEPTED: given password with registered user %s\n", user)); @@ -494,7 +507,7 @@ BOOL authorise_login(int snum,char *user,char *password, int pwlen, if (!user_ok(user2,snum)) continue; - if (password_ok(user2,password, pwlen)) { + if (password_ok(user2,password)) { ok = True; fstrcpy(user,user2); DEBUG(3,("authorise_login: ACCEPTED: session list username (%s) \ @@ -526,7 +539,7 @@ and given password ok\n", user)); for (auser=strtok(user_list,LIST_SEP); auser && !ok; auser = strtok(NULL,LIST_SEP)) { if (*auser == '@') { - auser = validate_group(auser+1,password,pwlen,snum); + auser = validate_group(auser+1,password,snum); if (auser) { ok = True; fstrcpy(user,auser); @@ -536,7 +549,7 @@ and given password ok (%s)\n", user)); } else { fstring user2; fstrcpy(user2,auser); - if (user_ok(user2,snum) && password_ok(user2,password,pwlen)) { + if (user_ok(user2,snum) && password_ok(user2,password)) { ok = True; fstrcpy(user,user2); DEBUG(3,("authorise_login: ACCEPTED: user list username \ diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c index ca7bcb9c5f..b60738d23d 100644 --- a/source3/smbd/reply.c +++ b/source3/smbd/reply.c @@ -159,14 +159,16 @@ int reply_tcon(connection_struct *conn, int pwlen=0; NTSTATUS nt_status; char *p; - + DATA_BLOB password_blob; + START_PROFILE(SMBtcon); *service = *password = *dev = 0; p = smb_buf(inbuf)+1; p += srvstr_pull(inbuf, service, p, sizeof(service), -1, STR_TERMINATE) + 1; - p += srvstr_pull(inbuf, password, p, sizeof(password), -1, STR_TERMINATE) + 1; + pwlen = srvstr_pull(inbuf, password, p, sizeof(password), -1, STR_TERMINATE) + 1; + p += pwlen; p += srvstr_pull(inbuf, dev, p, sizeof(dev), -1, STR_TERMINATE) + 1; p = strrchr_m(service,'\\'); @@ -174,7 +176,9 @@ int reply_tcon(connection_struct *conn, pstrcpy(service, p+1); } - conn = make_connection(service,password,pwlen,dev,vuid,&nt_status); + password_blob = data_blob(password, pwlen+1); + + conn = make_connection(service,password_blob,dev,vuid,&nt_status); if (!conn) { END_PROFILE(SMBtcon); @@ -200,16 +204,17 @@ int reply_tcon(connection_struct *conn, int reply_tcon_and_X(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize) { fstring service; - pstring password; + DATA_BLOB password; pstring devicename; NTSTATUS nt_status; uint16 vuid = SVAL(inbuf,smb_uid); int passlen = SVAL(inbuf,smb_vwv3); pstring path; char *p, *q; - START_PROFILE(SMBtconX); - - *service = *password = *devicename = 0; + extern BOOL global_encrypted_passwords_negotiated; + START_PROFILE(SMBtconX); + + *service = *devicename = 0; /* we might have to close an old one */ if ((SVAL(inbuf,smb_vwv2) & 0x1) && conn) { @@ -220,17 +225,17 @@ int reply_tcon_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt return ERROR_DOS(ERRDOS,ERRbuftoosmall); } - memcpy(password,smb_buf(inbuf),passlen); - password[passlen]=0; + if (global_encrypted_passwords_negotiated) { + password = data_blob(smb_buf(inbuf),passlen); + } else { + password = data_blob(smb_buf(inbuf),passlen+1); + /* Ensure correct termination */ + password.data[passlen]=0; + } + p = smb_buf(inbuf) + passlen; p += srvstr_pull(inbuf, path, p, sizeof(path), -1, STR_TERMINATE); - if (passlen != 24) { - if (strequal(password," ")) - *password = 0; - passlen = strlen(password); - } - /* * the service name can be either: \\server\share * or share directly like on the DELL PowerVault 705 @@ -250,7 +255,7 @@ int reply_tcon_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt DEBUG(4,("Got device type %s\n",devicename)); - conn = make_connection(service,password,passlen,devicename,vuid,&nt_status); + conn = make_connection(service,password,devicename,vuid,&nt_status); if (!conn) { END_PROFILE(SMBtconX); diff --git a/source3/smbd/service.c b/source3/smbd/service.c index 37f4610b9d..f6296201ae 100644 --- a/source3/smbd/service.c +++ b/source3/smbd/service.c @@ -79,7 +79,7 @@ BOOL set_current_service(connection_struct *conn,BOOL do_chdir) Add a home service. Returns the new service number or -1 if fail. ****************************************************************************/ -int add_home_service(char *service, char *homedir) +int add_home_service(const char *service, const char *homedir) { int iHomeService; int iService; @@ -320,8 +320,8 @@ static void set_admin_user(connection_struct *conn) Make a connection to a service. ****************************************************************************/ -connection_struct *make_connection(char *service,char *password, - int pwlen, char *dev,uint16 vuid, NTSTATUS *status) +connection_struct *make_connection(char *service, DATA_BLOB password, + char *dev,uint16 vuid, NTSTATUS *status) { int snum; struct passwd *pass = NULL; @@ -361,7 +361,7 @@ connection_struct *make_connection(char *service,char *password, if (validated_username(vuid)) { fstring unix_username; fstrcpy(unix_username,validated_username(vuid)); - return(make_connection(unix_username,password,pwlen,dev,vuid,status)); + return(make_connection(unix_username,password,dev,vuid,status)); } } else { /* Security = share. Try with current_user_info.smb_name @@ -370,7 +370,7 @@ connection_struct *make_connection(char *service,char *password, fstring unix_username; fstrcpy(unix_username,current_user_info.smb_name); map_username(unix_username); - return(make_connection(unix_username,password,pwlen,dev,vuid,status)); + return(make_connection(unix_username,password,dev,vuid,status)); } } } @@ -387,7 +387,7 @@ connection_struct *make_connection(char *service,char *password, /* shall we let them in? */ - if (!authorise_login(snum,user,password,pwlen,&guest,&force,vuid)) { + if (!authorise_login(snum,user,password,&guest,&force,vuid)) { DEBUG( 2, ( "Invalid username/password for %s [%s]\n", service, user ) ); *status = NT_STATUS_WRONG_PASSWORD; return NULL; diff --git a/source3/smbd/sesssetup.c b/source3/smbd/sesssetup.c index 2d9f624b80..5331127cb5 100644 --- a/source3/smbd/sesssetup.c +++ b/source3/smbd/sesssetup.c @@ -264,14 +264,16 @@ static int reply_spnego_auth(connection_struct *conn, char *inbuf, char *outbuf, DATA_BLOB auth; char *workgroup, *user, *machine; DATA_BLOB lmhash, nthash, sess_key; + DATA_BLOB plaintext_password = data_blob(NULL, 0); + DATA_BLOB sec_blob; uint32 ntlmssp_command, neg_flags; NTSTATUS nt_status; int sess_vuid; - gid_t gid; - uid_t uid; - char *full_name; char *p; - const struct passwd *pw; + char chal[8]; + + auth_usersupplied_info *user_info = NULL; + auth_serversupplied_info *server_info = NULL; if (!spnego_parse_auth(blob1, &auth)) { #if 0 @@ -305,36 +307,40 @@ static int reply_spnego_auth(connection_struct *conn, char *inbuf, char *outbuf, file_save("lmhash1.dat", lmhash.data, lmhash.length); #endif - nt_status = pass_check_smb(user, user, - workgroup, machine, - lmhash.data, - lmhash.length, - nthash.data, - nthash.length); - - data_blob_free(&nthash); + if (!last_challenge(chal)) { + DEBUG(0,("Encrypted login but no challange set!\n")); + return ERROR_NT(NT_STATUS_LOGON_FAILURE); + } + sec_blob = data_blob(chal, 8); + if (!sec_blob.data) { + return ERROR_NT(NT_STATUS_NO_MEMORY); + } + + if (!make_user_info_map(&user_info, + user, workgroup, + machine, sec_blob, + lmhash, nthash, + plaintext_password, + neg_flags, True)) { + return ERROR_NT(NT_STATUS_NO_MEMORY); + } + + nt_status = check_password(user_info, &server_info); + + free_user_info(&user_info); + data_blob_free(&lmhash); - + + data_blob_free(&nthash); + if (!NT_STATUS_IS_OK(nt_status)) { - return ERROR_NT(nt_status); + return ERROR_NT(nt_status_squash(nt_status)); } - /* the password is good - let them in */ - pw = smb_getpwnam(user,False); - if (!pw) { - DEBUG(1,("Username %s is invalid on this system\n",user)); - return ERROR_NT(NT_STATUS_LOGON_FAILURE); - } - gid = pw->pw_gid; - uid = pw->pw_uid; - full_name = pw->pw_gecos; - - sess_vuid = register_vuid(uid,gid,user,user,workgroup,False, full_name); + sess_vuid = register_vuid(server_info, user, False); - free(user); - free(workgroup); - free(machine); - + free_server_info(&server_info); + if (sess_vuid == -1) { return ERROR_NT(NT_STATUS_LOGON_FAILURE); } @@ -360,30 +366,16 @@ reply to a session setup spnego anonymous packet static int reply_spnego_anonymous(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize) { - char *user; int sess_vuid; - gid_t gid; - uid_t uid; - char *full_name; char *p; - const struct passwd *pw; + auth_serversupplied_info *server_info = NULL; DEBUG(3,("Got anonymous request\n")); - user = lp_guestaccount(-1); - - /* the password is good - let them in */ - pw = smb_getpwnam(user,False); - if (!pw) { - DEBUG(1,("Guest username %s is invalid on this system\n",user)); - return ERROR_NT(NT_STATUS_LOGON_FAILURE); - } - gid = pw->pw_gid; - uid = pw->pw_uid; - full_name = pw->pw_gecos; - - sess_vuid = register_vuid(uid,gid,user,user,lp_workgroup(),True,full_name); - + make_server_info_guest(&server_info); + sess_vuid = register_vuid(server_info, lp_guestaccount(-1), False); + free_server_info(&server_info); + if (sess_vuid == -1) { return ERROR_NT(NT_STATUS_LOGON_FAILURE); } @@ -414,7 +406,7 @@ static int reply_sesssetup_and_X_spnego(connection_struct *conn, char *inbuf,cha extern uint32 global_client_caps; int ret; - DEBUG(3,("Doing spego session setup\n")); + DEBUG(3,("Doing spnego session setup\n")); if (global_client_caps == 0) { global_client_caps = IVAL(inbuf,smb_vwv10); @@ -464,16 +456,11 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf, int length,int bufsize) { int sess_vuid; - gid_t gid; - uid_t uid; - char* full_name; int smb_bufsize; - int smb_apasslen = 0; - pstring smb_apasswd; - int smb_ntpasslen = 0; - pstring smb_ntpasswd; + DATA_BLOB lm_resp; + DATA_BLOB nt_resp; + DATA_BLOB plaintext_password; pstring user; - pstring orig_user; fstring domain; fstring native_os; fstring native_lanman; @@ -486,9 +473,18 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf, extern fstring remote_machine; extern userdom_struct current_user_info; extern int max_send; + + auth_usersupplied_info *user_info = NULL; + auth_serversupplied_info *server_info = NULL; + BOOL doencrypt = global_encrypted_passwords_negotiated; + START_PROFILE(SMBsesssetupX); + ZERO_STRUCT(lm_resp); + ZERO_STRUCT(nt_resp); + ZERO_STRUCT(plaintext_password); + DEBUG(3,("wct=%d flg2=0x%x\n", CVAL(inbuf, smb_wct), SVAL(inbuf, smb_flg2))); /* a SPNEGO session setup has 12 command words, whereas a normal @@ -503,28 +499,35 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf, return ERROR_NT(NT_STATUS_UNSUCCESSFUL); } - *smb_apasswd = *smb_ntpasswd = 0; - smb_bufsize = SVAL(inbuf,smb_vwv2); - + if (Protocol < PROTOCOL_NT1) { - smb_apasslen = SVAL(inbuf,smb_vwv7); - if (smb_apasslen > MAX_PASS_LEN) { + uint16 passlen1 = SVAL(inbuf,smb_vwv7); + if (passlen1 > MAX_PASS_LEN) { return ERROR_DOS(ERRDOS,ERRbuftoosmall); } - memcpy(smb_apasswd,smb_buf(inbuf),smb_apasslen); - srvstr_pull(inbuf, user, smb_buf(inbuf)+smb_apasslen, sizeof(user), -1, STR_TERMINATE); - - if (!doencrypt && (lp_security() != SEC_SERVER)) { - smb_apasslen = strlen(smb_apasswd); + if (doencrypt) { + lm_resp = data_blob(smb_buf(inbuf), passlen1); + } else { + plaintext_password = data_blob(smb_buf(inbuf), passlen1+1); + if (!plaintext_password.data) { + DEBUG(0,("reply_sesssetup_and_X: malloc failed for plaintext_password!\n")); + return ERROR_NT(NT_STATUS_NO_MEMORY); + } else { + /* Ensure null termination */ + plaintext_password.data[passlen1] = 0; + } } + + srvstr_pull(inbuf, user, smb_buf(inbuf)+passlen1, sizeof(user), -1, STR_TERMINATE); + } else { uint16 passlen1 = SVAL(inbuf,smb_vwv7); uint16 passlen2 = SVAL(inbuf,smb_vwv8); enum remote_arch_types ra_type = get_remote_arch(); char *p = smb_buf(inbuf); - + if(global_client_caps == 0) global_client_caps = IVAL(inbuf,smb_vwv11); @@ -539,16 +542,13 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf, } } - if (passlen1 != 24 && passlen2 < 24) - doencrypt = False; - if (passlen1 > MAX_PASS_LEN) { return ERROR_DOS(ERRDOS,ERRbuftoosmall); } - + passlen1 = MIN(passlen1, MAX_PASS_LEN); passlen2 = MIN(passlen2, MAX_PASS_LEN); - + if (!doencrypt) { /* both Win95 and WinNT stuff up the password lengths for non-encrypting systems. Uggh. @@ -591,23 +591,20 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf, passlen1 = 1; } } - + /* Save the lanman2 password and the NT md4 password. */ - smb_apasslen = passlen1; - memcpy(smb_apasswd,p,smb_apasslen); - - smb_ntpasslen = passlen2; - memcpy(smb_ntpasswd,p+passlen1,smb_ntpasslen); - - if (smb_apasslen != 24 || !doencrypt) { - /* trim the password */ - smb_apasslen = strlen(smb_apasswd); - - /* wfwg sometimes uses a space instead of a null */ - if (strequal(smb_apasswd," ")) { - smb_apasslen = 0; - *smb_apasswd = 0; - } + + if ((doencrypt) && (passlen1 != 0) && (passlen1 != 24)) { + doencrypt = False; + } + + if (doencrypt) { + lm_resp = data_blob(p, passlen1); + nt_resp = data_blob(p+passlen1, passlen2); + } else { + plaintext_password = data_blob(p, passlen1+1); + /* Ensure null termination */ + plaintext_password.data[passlen1] = 0; } p += passlen1 + passlen2; @@ -630,15 +627,29 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf, return ERROR_NT(NT_STATUS_LOGON_FAILURE); } - if (lp_security() == SEC_SHARE) { - /* in share level we should ignore any passwords */ - smb_ntpasslen = 0; - smb_apasslen = 0; + DEBUG(3,("sesssetupX:name=[%s]\\[%s]@[%s]\n", domain, user, remote_machine)); + + /* If no username is sent use the guest account */ + if (!*user) { + pstrcpy(user,lp_guestaccount(-1)); guest = True; } + pstrcpy(current_user_info.smb_name,user); + + reload_services(True); + + if (lp_security() == SEC_SHARE) { + /* in share level we should ignore any passwords */ + + data_blob_free(&lm_resp); + data_blob_free(&nt_resp); + data_blob_free(&plaintext_password); - DEBUG(3,("sesssetupX:name=[%s]\\[%s]@[%s]\n",user, domain, remote_machine)); + guest = True; + map_username(user); + add_session_user(user); + } if (done_sesssetup && lp_restrict_anonymous()) { /* tests show that even if browsing is done over @@ -649,106 +660,61 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf, * only deny connections that have no session * information. If a domain has been provided, then * it's not a purely anonymous connection. AAB */ - if (!*user && !*smb_apasswd && !*domain) { + if (!*user && !*domain) { DEBUG(0, ("restrict anonymous is True and anonymous connection attempted. Denying access.\n")); + + data_blob_free(&lm_resp); + data_blob_free(&nt_resp); + data_blob_free(&plaintext_password); + END_PROFILE(SMBsesssetupX); return ERROR_DOS(ERRDOS,ERRnoaccess); } } - - /* If no username is sent use the guest account */ - if (!*user) { - pstrcpy(user,lp_guestaccount(-1)); - guest = True; - } - - pstrcpy(current_user_info.smb_name,user); - - reload_services(True); - - /* - * Save the username before mapping. We will use - * the original username sent to us for security=server - * and security=domain checking. - */ - - pstrcpy( orig_user, user); - - /* - * Always try the "DOMAIN\user" lookup first, as this is the most - * specific case. If this fails then try the simple "user" lookup. - * But don't do this for guests, as this is always a local user. - */ if (!guest) { - pstring dom_user; - - /* Work out who's who */ - - slprintf(dom_user, sizeof(dom_user) - 1,"%s%s%s", - domain, lp_winbind_separator(), user); - - if (sys_getpwnam(dom_user) != NULL) { - pstrcpy(user, dom_user); - DEBUG(3,("Using unix username %s\n", dom_user)); + NTSTATUS nt_status; + if (!make_user_info_for_reply(&user_info, + user, domain, + lm_resp, nt_resp, + plaintext_password, doencrypt)) { + return ERROR_NT(NT_STATUS_NO_MEMORY); } - /* - * Pass the user through the NT -> unix user mapping - * function. - */ + nt_status = check_password(user_info, &server_info); - (void)map_username(user); + free_user_info(&user_info); - /* - * Do any UNIX username case mangling. - */ - smb_getpwnam(user, True); - } - - add_session_user(user); - - if (!guest) { - NTSTATUS nt_status; - nt_status = pass_check_smb(orig_user, user, - domain, remote_machine, - (unsigned char *)smb_apasswd, - smb_apasslen, - (unsigned char *)smb_ntpasswd, - smb_ntpasslen); - - if NT_STATUS_IS_OK(nt_status) { - - } else if NT_STATUS_EQUAL(nt_status, NT_STATUS_NO_SUCH_USER) { - if ((lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_USER) || - (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD)) { - DEBUG(3,("No such user %s [%s] - using guest account\n",user, domain)); - pstrcpy(user,lp_guestaccount(-1)); - guest = True; - } else { - /* Match WinXP and don't give the game away */ - return ERROR_NT(NT_STATUS_LOGON_FAILURE); - } - } else if NT_STATUS_EQUAL(nt_status, NT_STATUS_WRONG_PASSWORD) { - if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD) { - pstrcpy(user,lp_guestaccount(-1)); - DEBUG(3,("Registered username %s for guest access\n",user)); - guest = True; - } else { + data_blob_free(&lm_resp); + data_blob_free(&nt_resp); + data_blob_free(&plaintext_password); + + if (!NT_STATUS_IS_OK(nt_status)) { + if NT_STATUS_EQUAL(nt_status, NT_STATUS_NO_SUCH_USER) { + if ((lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_USER) || + (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD)) { + DEBUG(3,("No such user %s [%s] - using guest account\n",user, domain)); + pstrcpy(user,lp_guestaccount(-1)); + guest = True; + + } + } else if NT_STATUS_EQUAL(nt_status, NT_STATUS_WRONG_PASSWORD) { + if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD) { + pstrcpy(user,lp_guestaccount(-1)); + DEBUG(3,("Registered username %s for guest access\n",user)); + guest = True; + } /* Match WinXP and don't give the game away */ return ERROR_NT(NT_STATUS_LOGON_FAILURE); } - } else { - return ERROR_NT(nt_status); + + if (!guest) { + free_server_info(&server_info); + return ERROR_NT(nt_status_squash(nt_status)); + } } } - if (!strequal(user,lp_guestaccount(-1)) && - lp_servicenumber(user) < 0) { - add_home_service(user,get_user_home_dir(user)); - } - - /* it's ok - setup a reply */ if (Protocol < PROTOCOL_NT1) { set_message(outbuf,3,0,True); @@ -763,30 +729,26 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf, /* perhaps grab OS version here?? */ } - /* Set the correct uid in the outgoing and incoming packets - We will use this on future requests to determine which - user we should become. - */ - { - const struct passwd *pw = smb_getpwnam(user,False); - if (!pw) { - DEBUG(1,("Username %s is invalid on this system\n",user)); - END_PROFILE(SMBsesssetupX); - return ERROR_NT(NT_STATUS_LOGON_FAILURE); + if (guest) { + SSVAL(outbuf,smb_vwv2,1); + free_server_info(&server_info); + make_server_info_guest(&server_info); + } else { + const char *home_dir = pdb_get_homedir(server_info->sam_account); + const char *username = pdb_get_username(server_info->sam_account); + if ((home_dir && *home_dir) + && (lp_servicenumber(username) < 0)) { + add_home_service(username, home_dir); } - gid = pw->pw_gid; - uid = pw->pw_uid; - full_name = pw->pw_gecos; } - - if (guest) - SSVAL(outbuf,smb_vwv2,1); - + /* register the name and uid as being validated, so further connections to a uid can get through without a password, on the same VC */ - - sess_vuid = register_vuid(uid,gid,user,orig_user,domain,guest, full_name); - + + sess_vuid = register_vuid(server_info, user, guest); + + free_server_info(&server_info); + if (sess_vuid == -1) { return ERROR_NT(NT_STATUS_LOGON_FAILURE); } |