/* * This file is a part of Winix * and is distributed under the 2-Clause BSD licence. * Author: Tomasz Sowa */ /* * Copyright (c) 2011-2021, Tomasz Sowa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * */ #include "passwd.h" #include "core/slog.h" #include "functions/functions.h" namespace Winix { namespace Fun { Passwd::Passwd() { fun.url = L"passwd"; } bool Passwd::HasAccess() { // a not logged user can use this function to reset his password return true; } bool Passwd::IsPasswordCorrect(const std::wstring & pass, const std::wstring & conf_pass, bool use_ses_log) { if( pass != conf_pass ) { log << log2 << "Passwd: passwords are different" << logend; if( use_ses_log ) slog << logerror << T("adduser_err_passwords_different") << logend; return false; } if( pass.size() < config->pass_min_size ) { log << log2 << "Passwd: password is too small" << logend; if( use_ses_log ) slog << logerror << T("adduser_err_password_too_small") << " " << config->pass_min_size << " " << T("adduser_err_password_too_small2") << logend; return false; } if( pass.size() > WINIX_ACCOUNT_MAX_PASSWORD_SIZE ) { log << log2 << "Passwd: password can't be longer than: " << WINIX_ACCOUNT_MAX_PASSWORD_SIZE << " characters" << logend; if( use_ses_log ) slog << logerror << T("adduser_err_password_too_big") << " " << WINIX_ACCOUNT_MAX_PASSWORD_SIZE << " " << T("adduser_err_password_too_big2") << logend; return false; } return true; } bool Passwd::ChangePassword(long user_id, const std::wstring & new_password) { bool result = false; User * puser = system->users.GetUser(user_id); if( puser ) { puser->has_pass = true; puser->password = new_password; system->crypt.PassHashCrypt(*puser); result = puser->update(); if( result ) log << log2 << "Passwd: password for user " << puser->login << " has been changed" << logend; else log << log1 << "Passwd: I cannot change password -- database problem" << logend; } else { log << log1 << "Passwd: there is no a user with id: " << user_id << logend; } return result; } void Passwd::ChangePassword(User * puser) { long user_id; const std::wstring & pass_cur = cur->request->PostVar(L"passwordcur"); const std::wstring & pass_new = cur->request->PostVar(L"passwordnew"); const std::wstring & pass_conf = cur->request->PostVar(L"passwordconfirm"); if( !cur->session->puser->is_super_user && !functions->fun_login.CheckUserPass(puser->login, pass_cur, user_id) ) { log << log3 << "Passwd: incorrect current password" << logend; slog << logerror << T("passwd_err_bad_current_password") << logend; return; } if( !IsPasswordCorrect(pass_new, pass_conf, true) ) return; if( ChangePassword(puser->id, pass_new) ) { slog << loginfo << T("passwd_password_changed") << logend; system->RedirectToLastItem(); } } bool Passwd::SetNewPassword(User * puser, bool use_ses_log) { bool result = false; const std::wstring & pass = cur->request->PostVar(L"passwordnew"); const std::wstring & pass_conf = cur->request->PostVar(L"passwordconfirm"); if( IsPasswordCorrect(pass, pass_conf, use_ses_log) ) { if( ChangePassword(puser->id, pass) ) { result = true; if( use_ses_log ) slog << loginfo << T("pw_password_changed") << logend; } else { if( use_ses_log ) slog << logerror << T("service_unavailable") << logend; } } return result; } bool Passwd::ResetPassword(User * puser, long code, bool use_ses_log, bool only_check_access) { std::wstring * user_code_str = puser->admin_env.get_wstr(L"password_change_code"); if( user_code_str ) { if( Tol(*user_code_str) == code ) { if( only_check_access ) return true; else return SetNewPassword(puser, use_ses_log); } else { log << log2 << "Passwd: incorrect change password code" << logend; if( use_ses_log ) slog << logerror << T(L"incorrect_change_password_code") << logend; } } else { log << log1 << "Passwd: there is no change password code in admin environment" << logend; if( use_ses_log ) slog << loginfo << T(L"password_cannot_be_changed") << logend; } return false; } bool Passwd::ResetPassword(const std::wstring & login, long code, bool use_ses_log, bool only_check_access) { bool result = false; User * puser = system->users.GetUser(login); if( puser ) { long t = static_cast(cur->request->start_time); if( puser->admin_env.to_long(L"password_change_time") + config->reset_password_code_expiration_time > t ) { result = ResetPassword(puser, code, use_ses_log, only_check_access); } else { log << log2 << "Passwd: the code has expired" << logend; if( use_ses_log ) slog << logerror << T(L"code_expired") << logend; } } else { log << log1 << "Passwd: there is no a user: " << login << logend; } return result; } void Passwd::ResetPassword() { const std::wstring & login = cur->request->PostVar(L"login"); long code = Tol(cur->request->PostVar(L"code")); if( ResetPassword(login, code, true, false) ) system->RedirectToLastItem(); } void Passwd::ShowResetPasswordForm() { const std::wstring & login = cur->request->ParamValue(L"login"); long code = Tol(cur->request->ParamValue(L"code")); if( !login.empty() ) { if( !ResetPassword(login, code, true, true) ) system->RedirectToLastItem(); } else { system->RedirectToLastItem(); } } /* if you are a root (super_user) you can change a password for everyone (the html form has a select option) but if you are not a root you can change only your password and you should provide your current password as well */ void Passwd::MakePost() { const std::wstring * plogin; // CHECK ME // may it is better to check first for 'resetpassword' // now if a user is logged then 'resetpassword' has no effect // actually 'resetpassword' would be used for other user if( cur->session->puser ) { if( cur->session->puser->is_super_user ) plogin = &cur->request->PostVar(L"login"); else plogin = &cur->session->puser->login; User * puser = system->users.GetUser(*plogin); if( puser ) ChangePassword(puser); else log << log1 << "Passwd: there is no such a user: " << *plogin << logend; } else if( cur->request->IsParam(L"resetpassword") ) { ResetPassword(); } } void Passwd::MakeGet() { if( cur->request->IsParam(L"resetpassword") ) ShowResetPasswordForm(); else if( !cur->session->puser ) cur->request->status = WINIX_ERR_PERMISSION_DENIED; } } // namespace } // namespace Winix