// swad_password.c: Users' passwords /* SWAD (Shared Workspace At a Distance), is a web platform developed at the University of Granada (Spain), and used to support university teaching. This file is part of SWAD core. Copyright (C) 1999-2019 Antonio Caņas Vargas This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ /*****************************************************************************/ /********************************* Headers ***********************************/ /*****************************************************************************/ #define _GNU_SOURCE // For asprintf #include // For asprintf #include // For system, getenv, etc. #include // For string functions #include // For the macro WEXITSTATUS #include // For unlink #include "swad_box.h" #include "swad_database.h" #include "swad_enrolment.h" #include "swad_form.h" #include "swad_global.h" #include "swad_HTML.h" #include "swad_ID.h" #include "swad_password.h" #include "swad_parameter.h" #include "swad_user.h" /*****************************************************************************/ /************** External global variables from others modules ****************/ /*****************************************************************************/ extern struct Globals Gbl; /*****************************************************************************/ /***************************** Private constants *****************************/ /*****************************************************************************/ // If there are X users with the same password, // it means than the password is trivial // and another user can not change his/her password to this #define Pwd_MAX_OTHER_USERS_USING_THE_SAME_PASSWORD 2 /*****************************************************************************/ /******************************* Private types *******************************/ /*****************************************************************************/ /*****************************************************************************/ /***************************** Private variables *****************************/ /*****************************************************************************/ const char *Pwd_PASSWORD_SECTION_ID = "password_section"; /*****************************************************************************/ /***************************** Private prototypes ****************************/ /*****************************************************************************/ static void Pwd_CheckAndUpdateNewPwd (struct UsrData *UsrDat); static void Pwd_PutLinkToSendNewPasswdParams (void); static void Pwd_CreateANewPassword (char PlainPassword[Pwd_MAX_BYTES_PLAIN_PASSWORD + 1]); static bool Pwd_CheckIfPasswdIsUsrIDorName (const char *PlainPassword); static unsigned Pwd_GetNumOtherUsrsWhoUseThisPassword (const char *EncryptedPassword,long UsrCod); /*****************************************************************************/ /************* Get parameter with my plain password from a form **************/ /*****************************************************************************/ void Pwd_GetParamUsrPwdLogin (void) { /***** Get plain password from form *****/ Par_GetParToText ("UsrPwd",Gbl.Usrs.Me.LoginPlainPassword, Pwd_MAX_BYTES_PLAIN_PASSWORD); /***** Encrypt password *****/ Cry_EncryptSHA512Base64 (Gbl.Usrs.Me.LoginPlainPassword,Gbl.Usrs.Me.LoginEncryptedPassword); } /*****************************************************************************/ /**** Check if login password is the same as current password in database ****/ /*****************************************************************************/ // Returns true if there's no current password in database, or if login password is the same // Returns false if there's a current password in database and is not the same as the login password bool Pwd_CheckCurrentPassword (void) { return (Gbl.Usrs.Me.UsrDat.Password[0] ? !strcmp (Gbl.Usrs.Me.LoginEncryptedPassword,Gbl.Usrs.Me.UsrDat.Password) : true); } /*****************************************************************************/ /**** Check if login password is the same as current password in database ****/ /*****************************************************************************/ // Returns true if there's pending password in database and login password is the same // Returns false if there's no a pending password in database, or if pending password is not the same as the login password bool Pwd_CheckPendingPassword (void) { MYSQL_RES *mysql_res; MYSQL_ROW row; /***** Get pending password from database *****/ if (DB_QuerySELECT (&mysql_res,"can not get pending password", "SELECT PendingPassword FROM pending_passwd" " WHERE UsrCod=%ld", Gbl.Usrs.Me.UsrDat.UsrCod)) { /* Get encrypted pending password */ row = mysql_fetch_row (mysql_res); Str_Copy (Gbl.Usrs.Me.PendingPassword,row[0], Pwd_BYTES_ENCRYPTED_PASSWORD); } else Gbl.Usrs.Me.PendingPassword[0] = '\0'; /***** Free structure that stores the query result *****/ DB_FreeMySQLResult (&mysql_res); return (Gbl.Usrs.Me.PendingPassword[0] ? !strcmp (Gbl.Usrs.Me.LoginEncryptedPassword,Gbl.Usrs.Me.PendingPassword) : false); } /*****************************************************************************/ /************ Assign my pending password to my current password **************/ /*****************************************************************************/ void Pwd_AssignMyPendingPasswordToMyCurrentPassword (void) { /***** Update my current password in database *****/ DB_QueryUPDATE ("can not update your password", "UPDATE usr_data SET Password='%s'" " WHERE UsrCod=%ld", Gbl.Usrs.Me.PendingPassword, Gbl.Usrs.Me.UsrDat.UsrCod); /***** Update my current password *****/ Str_Copy (Gbl.Usrs.Me.UsrDat.Password,Gbl.Usrs.Me.PendingPassword, Pwd_BYTES_ENCRYPTED_PASSWORD); } /*****************************************************************************/ /*********************** Update my password in database **********************/ /*****************************************************************************/ void Pwd_UpdateMyPwd (void) { extern const char *Txt_You_have_not_entered_your_password_correctly; char PlainPassword[Pwd_MAX_BYTES_PLAIN_PASSWORD + 1]; /***** Get plain password from form *****/ Par_GetParToText ("UsrPwd",PlainPassword,Pwd_MAX_BYTES_PLAIN_PASSWORD); /***** Encrypt password *****/ Cry_EncryptSHA512Base64 (PlainPassword,Gbl.Usrs.Me.LoginEncryptedPassword); /***** Check current password *****/ if (Pwd_CheckCurrentPassword ()) /***** Check and update new password *****/ Pwd_CheckAndUpdateNewPwd (&Gbl.Usrs.Me.UsrDat); else Ale_CreateAlert (Ale_WARNING,Pwd_PASSWORD_SECTION_ID, Txt_You_have_not_entered_your_password_correctly); } /*****************************************************************************/ /********************* Update another user's password ************************/ /*****************************************************************************/ void Pwd_UpdateOtherUsrPwd (void) { /***** Get other user's code from form and get user's data *****/ if (Usr_GetParamOtherUsrCodEncryptedAndGetUsrData ()) { if (Usr_ICanEditOtherUsr (&Gbl.Usrs.Other.UsrDat)) /***** Check and update password *****/ Pwd_CheckAndUpdateNewPwd (&Gbl.Usrs.Other.UsrDat); else Ale_ShowAlertUserNotFoundOrYouDoNotHavePermission (); } else // User not found Ale_ShowAlertUserNotFoundOrYouDoNotHavePermission (); } /*****************************************************************************/ /********************* Check and update new password *************************/ /*****************************************************************************/ static void Pwd_CheckAndUpdateNewPwd (struct UsrData *UsrDat) { extern const char *Txt_You_have_not_written_twice_the_same_new_password; extern const char *Txt_The_password_has_been_changed_successfully; char NewPlainPassword[2][Pwd_MAX_BYTES_PLAIN_PASSWORD + 1]; char NewEncryptedPassword[Pwd_BYTES_ENCRYPTED_PASSWORD + 1]; Par_GetParToText ("Paswd1",NewPlainPassword[0],Pwd_MAX_BYTES_PLAIN_PASSWORD); Par_GetParToText ("Paswd2",NewPlainPassword[1],Pwd_MAX_BYTES_PLAIN_PASSWORD); /***** Check if I have written twice the same password *****/ if (strcmp (NewPlainPassword[0],NewPlainPassword[1])) // Passwords don't match Ale_CreateAlert (Ale_WARNING,Pwd_PASSWORD_SECTION_ID, Txt_You_have_not_written_twice_the_same_new_password); else { Cry_EncryptSHA512Base64 (NewPlainPassword[0],NewEncryptedPassword); if (Pwd_SlowCheckIfPasswordIsGood (NewPlainPassword[0], NewEncryptedPassword, UsrDat->UsrCod)) // New password is good? { /* Update user's data */ Str_Copy (UsrDat->Password,NewEncryptedPassword, Pwd_BYTES_ENCRYPTED_PASSWORD); Ses_UpdateSessionDataInDB (); Enr_UpdateUsrData (UsrDat); Ale_CreateAlert (Ale_SUCCESS,Pwd_PASSWORD_SECTION_ID, Txt_The_password_has_been_changed_successfully); } } } /*****************************************************************************/ /*************** Show form to send a new password by email *******************/ /*****************************************************************************/ void Pwd_PutLinkToSendNewPasswd (void) { extern const char *Txt_Forgotten_password; Lay_PutContextualLinkIconText (ActReqSndNewPwd,NULL, Pwd_PutLinkToSendNewPasswdParams, "key.svg", Txt_Forgotten_password); } static void Pwd_PutLinkToSendNewPasswdParams (void) { Par_PutHiddenParamString ("UsrId",Gbl.Usrs.Me.UsrIdLogin); } /*****************************************************************************/ /*************** Show form to send a new password by email *******************/ /*****************************************************************************/ void Pwd_ShowFormSendNewPwd (void) { extern const char *Hlp_PROFILE_Password; extern const char *The_ClassFormInBox[The_NUM_THEMES]; extern const char *Txt_If_you_have_forgotten_your_password_; extern const char *Txt_Forgotten_password; extern const char *Txt_nick_email_or_ID; extern const char *Txt_Get_a_new_password; /***** Begin form *****/ Frm_StartForm (ActSndNewPwd); /***** Begin box *****/ Box_BoxBegin (NULL,Txt_Forgotten_password,NULL, Hlp_PROFILE_Password,Box_NOT_CLOSABLE); /***** Help text *****/ Ale_ShowAlert (Ale_INFO,Txt_If_you_have_forgotten_your_password_); /***** User's ID/nickname *****/ fprintf (Gbl.F.Out,"