// 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-2015 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 ***********************************/ /*****************************************************************************/ #include // For system, getenv, etc. #include // For string functions #include // For the macro WEXITSTATUS #include // For unlink #include "swad_database.h" #include "swad_enrollment.h" #include "swad_global.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 *****************************/ /*****************************************************************************/ /*****************************************************************************/ /***************************** Private prototypes ****************************/ /*****************************************************************************/ static void Pwd_PutLinkToSendNewPasswdParams (void); static void Pwd_CreateANewPassword (char PlainPassword[Pwd_MAX_LENGTH_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_LENGTH_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) { char Query[256+Cry_LENGTH_ENCRYPTED_STR_SHA512_BASE64]; MYSQL_RES *mysql_res; MYSQL_ROW row; /***** Get pending password from database *****/ sprintf (Query,"SELECT PendingPassword FROM pending_passwd" " WHERE UsrCod='%ld'", Gbl.Usrs.Me.UsrDat.UsrCod); if (DB_QuerySELECT (Query,&mysql_res,"can not get pending password")) { /* Get encrypted pending password */ row = mysql_fetch_row (mysql_res); strcpy (Gbl.Usrs.Me.PendingPassword,row[0]); } 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) { char Query[128+Cry_LENGTH_ENCRYPTED_STR_SHA512_BASE64]; /***** Update my current password in database *****/ sprintf (Query,"UPDATE usr_data SET Password='%s'" " WHERE UsrCod='%ld'", Gbl.Usrs.Me.PendingPassword, Gbl.Usrs.Me.UsrDat.UsrCod); DB_QueryUPDATE (Query,"can not update your password"); /***** Update my current password *****/ strcpy (Gbl.Usrs.Me.UsrDat.Password,Gbl.Usrs.Me.PendingPassword); } /*****************************************************************************/ /*********************** Change my password in database **********************/ /*****************************************************************************/ void Pwd_ActChgMyPwd1 (void) { extern const char *Txt_You_have_not_written_twice_the_same_new_password; extern const char *Txt_Your_password_has_been_changed_successfully; extern const char *Txt_You_have_not_entered_your_password_correctly; char PlainPassword[Pwd_MAX_LENGTH_PLAIN_PASSWORD+1]; char NewPlainPassword[2][Pwd_MAX_LENGTH_PLAIN_PASSWORD+1]; char NewEncryptedPassword[Cry_LENGTH_ENCRYPTED_STR_SHA512_BASE64+1]; /***** Get plain password from form *****/ Par_GetParToText ("UsrPwd",PlainPassword,Pwd_MAX_LENGTH_PLAIN_PASSWORD); /***** Encrypt password *****/ Cry_EncryptSHA512Base64 (PlainPassword,Gbl.Usrs.Me.LoginEncryptedPassword); Gbl.Usrs.Error = true; if (Pwd_CheckCurrentPassword ()) { Par_GetParToText ("Paswd1",NewPlainPassword[0],Pwd_MAX_LENGTH_PLAIN_PASSWORD); Par_GetParToText ("Paswd2",NewPlainPassword[1],Pwd_MAX_LENGTH_PLAIN_PASSWORD); /***** Check if I have written twice the same password *****/ if (strcmp (NewPlainPassword[0],NewPlainPassword[1])) // Passwords don't match strcpy (Gbl.Message,Txt_You_have_not_written_twice_the_same_new_password); else { Str_ChangeFormat (Str_FROM_FORM,Str_TO_TEXT, NewPlainPassword[0],Pwd_MAX_LENGTH_PLAIN_PASSWORD,true); Cry_EncryptSHA512Base64 (NewPlainPassword[0],NewEncryptedPassword); if (Pwd_SlowCheckIfPasswordIsGood (NewPlainPassword[0],NewEncryptedPassword,Gbl.Usrs.Me.UsrDat.UsrCod)) // New password is good? { strcpy (Gbl.Usrs.Me.UsrDat.Password,NewEncryptedPassword); Ses_UpdateSessionDataInDB (); Enr_UpdateUsrData (&Gbl.Usrs.Me.UsrDat); strcpy (Gbl.Message,Txt_Your_password_has_been_changed_successfully); Gbl.Usrs.Error = false; } } } else strcpy (Gbl.Message,Txt_You_have_not_entered_your_password_correctly); } void Pwd_ActChgMyPwd2 (void) { /***** Write error message when updating password *****/ Lay_ShowAlert (Gbl.Usrs.Error ? Lay_WARNING : Lay_INFO, Gbl.Message); /***** Retry? *****/ if (Gbl.Usrs.Error) Pwd_ShowFormChgPwd (); } /*****************************************************************************/ /*************** Show form to send a new password by e-mail ******************/ /*****************************************************************************/ void Pwd_PutLinkToSendNewPasswd (void) { extern const char *Txt_I_forgot_my_password; Act_PutContextualLink (ActReqSndNewPwd,Pwd_PutLinkToSendNewPasswdParams, "key",Txt_I_forgot_my_password); } static void Pwd_PutLinkToSendNewPasswdParams (void) { Par_PutHiddenParamString ("UsrId",Gbl.Usrs.Me.UsrIdLogin); } /*****************************************************************************/ /*************** Show form to send a new password by e-mail ******************/ /*****************************************************************************/ void Pwd_ShowFormSendNewPwd (void) { extern const char *The_ClassFormul[The_NUM_THEMES]; extern const char *Txt_If_you_have_forgotten_your_password_; extern const char *Txt_nick_email_or_ID; extern const char *Txt_Email_new_password; /***** Help text *****/ Lay_ShowAlert (Lay_INFO,Txt_If_you_have_forgotten_your_password_); /***** Start of form *****/ Act_FormStart (ActSndNewPwd); /***** User's ID/nickname *****/ fprintf (Gbl.F.Out,"
" "%s: " "" "
", The_ClassFormul[Gbl.Prefs.Theme],Txt_nick_email_or_ID,Usr_MAX_LENGTH_USR_LOGIN,Gbl.Usrs.Me.UsrIdLogin); /***** End form *****/ Lay_PutConfirmButton (Txt_Email_new_password); Act_FormEnd (); } /*****************************************************************************/ /*********************** Send a new password by e-mail ***********************/ /*****************************************************************************/ void Pwd_ChkIdLoginAndSendNewPwd (void) { extern const char *Txt_You_must_enter_your_nick_email_or_ID; extern const char *Txt_There_was_a_problem_sending_an_email_automatically; extern const char *Txt_If_you_have_written_your_ID_nickname_or_email_correctly_; extern const char *Txt_There_are_more_than_one_user_with_the_ID_X_Please_type_a_nick_or_email; struct ListUsrCods ListUsrCods; char NewRandomPlainPassword[Pwd_MAX_LENGTH_PLAIN_PASSWORD+1]; int ReturnCode; /***** Check if user's ID or nickname is not empty *****/ if (!Gbl.Usrs.Me.UsrIdLogin[0]) { Lay_ShowAlert (Lay_WARNING,Txt_You_must_enter_your_nick_email_or_ID); Pwd_ShowFormSendNewPwd (); return; } /***** Reset default list of users' codes *****/ ListUsrCods.NumUsrs = 0; ListUsrCods.Lst = NULL; /***** Check if user exists *****/ /* Check if user has typed his user's ID or his nickname */ if (Nck_CheckIfNickWithArrobaIsValid (Gbl.Usrs.Me.UsrIdLogin)) // 1: It's a nickname { if ((Gbl.Usrs.Me.UsrDat.UsrCod = Nck_GetUsrCodFromNickname (Gbl.Usrs.Me.UsrIdLogin)) > 0) { /* Get user's data */ ListUsrCods.NumUsrs = 1; Usr_AllocateListUsrCods (&ListUsrCods); ListUsrCods.Lst[0] = Gbl.Usrs.Other.UsrDat.UsrCod; } } else if (Mai_CheckIfEmailIsValid (Gbl.Usrs.Me.UsrIdLogin)) // 2: It's an e-mail { if ((Gbl.Usrs.Me.UsrDat.UsrCod = Mai_GetUsrCodFromEmail (Gbl.Usrs.Me.UsrIdLogin)) > 0) { /* Get user's data */ ListUsrCods.NumUsrs = 1; Usr_AllocateListUsrCods (&ListUsrCods); ListUsrCods.Lst[0] = Gbl.Usrs.Other.UsrDat.UsrCod; } } else // 3: It's not a nickname nor e-mail { // Users' IDs are always stored internally in capitals and without leading zeros Str_RemoveLeadingZeros (Gbl.Usrs.Me.UsrIdLogin); Str_ConvertToUpperText (Gbl.Usrs.Me.UsrIdLogin); if (ID_CheckIfUsrIDIsValid (Gbl.Usrs.Me.UsrIdLogin)) { /***** Allocate space for the list *****/ ID_ReallocateListIDs (&Gbl.Usrs.Me.UsrDat,1); // User has typed a user's ID strcpy (Gbl.Usrs.Me.UsrDat.IDs.List[0].ID,Gbl.Usrs.Me.UsrIdLogin); /* Get users' codes for this ID */ if (!ID_GetListUsrCodsFromUsrID (&Gbl.Usrs.Me.UsrDat,NULL,&ListUsrCods,true)) // Only confirmed IDs // If no users found with confirmed IDs, try to get all users (confirmed or not) ID_GetListUsrCodsFromUsrID (&Gbl.Usrs.Me.UsrDat,NULL,&ListUsrCods,false); // All users (confirmed or not) } } /***** Send a new password via e-mail when user exists *****/ if (ListUsrCods.NumUsrs) { if (ListUsrCods.NumUsrs == 1) { Usr_GetUsrDataFromUsrCod (&Gbl.Usrs.Me.UsrDat); // Get my data if (Gbl.Usrs.Me.UsrDat.Email[0]) switch ((ReturnCode = Pwd_SendNewPasswordByEmail (NewRandomPlainPassword))) { case 0: // Message sent successfully Pwd_SetMyPendingPassword (NewRandomPlainPassword); Lay_ShowAlert (Lay_INFO,Txt_If_you_have_written_your_ID_nickname_or_email_correctly_); break; case 1: Lay_ShowAlert (Lay_WARNING,Txt_There_was_a_problem_sending_an_email_automatically); break; default: sprintf (Gbl.Message,"Internal error: an email message has not been sent successfully." " Error code returned by the script: %d", ReturnCode); Lay_ShowAlert (Lay_ERROR,Gbl.Message); break; } else // I have no e-mail address /***** Help message *****/ Lay_ShowAlert (Lay_INFO,Txt_If_you_have_written_your_ID_nickname_or_email_correctly_); } else // ListUsrCods.NumUsrs > 1 { /***** Help message *****/ // TODO: This message allows to know if a ID exists in database (when no unique). This should be hidden! sprintf (Gbl.Message,Txt_There_are_more_than_one_user_with_the_ID_X_Please_type_a_nick_or_email, Gbl.Usrs.Me.UsrIdLogin); Lay_ShowAlert (Lay_WARNING,Gbl.Message); Pwd_ShowFormSendNewPwd (); } /***** Free list of users' codes *****/ Usr_FreeListUsrCods (&ListUsrCods); } else // ListUsrCods.NumUsrs == 0 ==> user does not exist /***** Help message *****/ Lay_ShowAlert (Lay_INFO,Txt_If_you_have_written_your_ID_nickname_or_email_correctly_); } /*****************************************************************************/ /*********************** Send a new password by e-mail ***********************/ /*****************************************************************************/ // Gbl.Usrs.Me.UsrDat must be filled // Return code returned by command int Pwd_SendNewPasswordByEmail (char NewRandomPlainPassword[Pwd_MAX_LENGTH_PLAIN_PASSWORD+1]) { extern const char *Txt_The_following_password_has_been_assigned_to_you_to_log_in_X_NO_HTML; extern const char *Txt_New_password_NO_HTML[Txt_NUM_LANGUAGES]; char Command[2048]; // Command to execute for sending an e-mail int ReturnCode; /***** Create temporary file for mail content *****/ Mai_CreateFileNameMail (); /***** Create a new random password *****/ Pwd_CreateANewPassword (NewRandomPlainPassword); /***** Write mail content into file and close file *****/ /* Welcome note */ Mai_WriteWelcomeNoteEMail (&Gbl.Usrs.Me.UsrDat); /* Message body */ fprintf (Gbl.Msg.FileMail,Txt_The_following_password_has_been_assigned_to_you_to_log_in_X_NO_HTML, Cfg_PLATFORM_SHORT_NAME,NewRandomPlainPassword, Cfg_HTTPS_URL_SWAD_CGI,(unsigned) (Cfg_TIME_TO_DELETE_OLD_PENDING_PASSWORDS/(24L*60L*60L)), Gbl.Usrs.Me.UsrDat.Email); /* Footer note */ Mai_WriteFootNoteEMail (Gbl.Prefs.Language); fclose (Gbl.Msg.FileMail); /***** Call the script to send an e-mail *****/ sprintf (Command,"%s \"%s\" \"%s\" \"%s\" \"%s\" \"%s\" \"[%s] %s\" \"%s\"", Cfg_COMMAND_SEND_AUTOMATIC_E_MAIL, Cfg_AUTOMATIC_EMAIL_SMTP_SERVER, Cfg_AUTOMATIC_EMAIL_SMTP_PORT, Cfg_AUTOMATIC_EMAIL_FROM, Gbl.Config.SMTPPassword, Gbl.Usrs.Me.UsrDat.Email, Cfg_PLATFORM_SHORT_NAME, Txt_New_password_NO_HTML[Gbl.Usrs.Me.UsrDat.Prefs.Language], Gbl.Msg.FileNameMail); ReturnCode = system (Command); if (ReturnCode == -1) Lay_ShowErrorAndExit ("Error when running script to send e-mail."); /***** Remove temporary file *****/ unlink (Gbl.Msg.FileNameMail); /***** Write message depending on return code *****/ return WEXITSTATUS (ReturnCode); } /*****************************************************************************/ /*********************** Create a new random password ************************/ /*****************************************************************************/ static void Pwd_CreateANewPassword (char PlainPassword[Pwd_MAX_LENGTH_PLAIN_PASSWORD+1]) { Str_CreateRandomAlphanumStr (PlainPassword,Pwd_MIN_LENGTH_PLAIN_PASSWORD); } /*****************************************************************************/ /*************************** Set my pending password *************************/ /*****************************************************************************/ void Pwd_SetMyPendingPassword (char PlainPassword[Pwd_MAX_LENGTH_PLAIN_PASSWORD+1]) { char Query[512]; /***** Encrypt my pending password *****/ Cry_EncryptSHA512Base64 (PlainPassword,Gbl.Usrs.Me.PendingPassword); /***** Remove expired pending passwords from database *****/ sprintf (Query,"DELETE FROM pending_passwd" " WHERE (UNIX_TIMESTAMP() > UNIX_TIMESTAMP(DateAndTime)+'%ld')", Cfg_TIME_TO_DELETE_OLD_PENDING_PASSWORDS); DB_QueryDELETE (Query,"can not remove expired pending passwords"); /***** Update my current password in database *****/ sprintf (Query,"REPLACE INTO pending_passwd (UsrCod,PendingPassword,DateAndTime)" " VALUES ('%ld','%s',NOW())", Gbl.Usrs.Me.UsrDat.UsrCod,Gbl.Usrs.Me.PendingPassword); DB_QueryREPLACE (Query,"can not create pending password"); } /*****************************************************************************/ /******************************** Update password ****************************/ /*****************************************************************************/ void Pwd_UpdateOtherPwd1 (void) { extern const char *Txt_You_have_not_written_twice_the_same_new_password; extern const char *Txt_The_X_password_has_been_changed_successfully; extern const char *Txt_User_not_found_or_you_do_not_have_permission_; char NewPlainPassword[2][Pwd_MAX_LENGTH_PLAIN_PASSWORD+1]; char NewEncryptedPassword[Cry_LENGTH_ENCRYPTED_STR_SHA512_BASE64+1]; Gbl.Usrs.Error = true; /***** Get other user's code from form and get user's data *****/ if (Usr_GetParamOtherUsrCodEncryptedAndGetUsrData ()) { if (Pwd_CheckIfICanChangeOtherUsrPassword (Gbl.Usrs.Other.UsrDat.UsrCod)) { Par_GetParToText ("Paswd1",NewPlainPassword[0],Pwd_MAX_LENGTH_PLAIN_PASSWORD); Par_GetParToText ("Paswd2",NewPlainPassword[1],Pwd_MAX_LENGTH_PLAIN_PASSWORD); if (strcmp (NewPlainPassword[0],NewPlainPassword[1])) // Paswords don't match strcpy (Gbl.Message,Txt_You_have_not_written_twice_the_same_new_password); else { Str_ChangeFormat (Str_FROM_FORM,Str_TO_TEXT, NewPlainPassword[0],Pwd_MAX_LENGTH_PLAIN_PASSWORD,true); Cry_EncryptSHA512Base64 (NewPlainPassword[0],NewEncryptedPassword); if (Pwd_SlowCheckIfPasswordIsGood (NewPlainPassword[0],NewEncryptedPassword,Gbl.Usrs.Other.UsrDat.UsrCod)) // Good password { /* Update other user's data */ strcpy (Gbl.Usrs.Other.UsrDat.Password,NewEncryptedPassword); Enr_UpdateUsrData (&Gbl.Usrs.Other.UsrDat); sprintf (Gbl.Message,Txt_The_X_password_has_been_changed_successfully, Gbl.Usrs.Other.UsrDat.FullName); Gbl.Usrs.Error = false; } } } else strcpy (Gbl.Message,Txt_User_not_found_or_you_do_not_have_permission_); } else // User not found strcpy (Gbl.Message,Txt_User_not_found_or_you_do_not_have_permission_); } void Pwd_UpdateOtherPwd2 (void) { /***** Write message when updating the password *****/ if (Gbl.Message[0]) Lay_ShowAlert (Gbl.Usrs.Error ? Lay_WARNING : Lay_INFO, Gbl.Message); if (Gbl.Usrs.Error) { /***** Try again *****/ Gbl.Usrs.Error = false; Pwd_ShowFormOthPwd (); } } /*****************************************************************************/ /************************ Check if a password is good ************************/ /*****************************************************************************/ bool Pwd_SlowCheckIfPasswordIsGood (const char *PlainPassword, const char *EncryptedPassword, long UsrCod) { extern const char *Txt_The_new_password_is_too_trivial_; /***** Check if password seems good by making fast checks *****/ if (!Pwd_FastCheckIfPasswordSeemsGood (PlainPassword)) return false; /***** Check if password is found in user's ID, first name or surnames of anybody *****/ if (Pwd_CheckIfPasswdIsUsrIDorName (PlainPassword)) // PlainPassword is a user's ID, name or surname { strcpy (Gbl.Message,Txt_The_new_password_is_too_trivial_); return false; } /***** Check if password is used by too many other users *****/ if (Pwd_GetNumOtherUsrsWhoUseThisPassword (EncryptedPassword,UsrCod) > Pwd_MAX_OTHER_USERS_USING_THE_SAME_PASSWORD) { strcpy (Gbl.Message,Txt_The_new_password_is_too_trivial_); return false; } return true; } /*****************************************************************************/ /***** Check if a password is a user's ID, a first name or a surname *********/ /*****************************************************************************/ static bool Pwd_CheckIfPasswdIsUsrIDorName (const char *PlainPassword) { char Query[128+3*Pwd_MAX_LENGTH_PLAIN_PASSWORD]; bool Found; /***** Get if password is found in user's ID from database *****/ sprintf (Query,"SELECT COUNT(*) FROM usr_IDs WHERE UsrID='%s'", PlainPassword); Found = (DB_QueryCOUNT (Query,"can not check if a password matches a user's ID") != 0); /***** Get if password is found in first name or surnames of anybody, from database *****/ if (!Found) { sprintf (Query,"SELECT COUNT(*) FROM usr_data" " WHERE FirstName='%s' OR Surname1='%s' OR Surname2='%s'", PlainPassword,PlainPassword,PlainPassword); Found = (DB_QueryCOUNT (Query,"can not check if a password matches a first name or a surname") != 0); } return Found; } /*****************************************************************************/ /************** Get the number of users who use yet a password ***************/ /*****************************************************************************/ static unsigned Pwd_GetNumOtherUsrsWhoUseThisPassword (const char *EncryptedPassword,long UsrCod) { char Query[512]; /***** Get number of other users who use a password from database *****/ /* Query database */ if (UsrCod > 0) sprintf (Query,"SELECT COUNT(*) FROM usr_data" " WHERE Password='%s' AND UsrCod<>'%ld'", EncryptedPassword,UsrCod); else sprintf (Query,"SELECT COUNT(*) FROM usr_data" " WHERE Password='%s'", EncryptedPassword); return (unsigned) DB_QueryCOUNT (Query,"can not check if a password is trivial"); } /*****************************************************************************/ /********************** Check if a password seems good ***********************/ /*****************************************************************************/ bool Pwd_FastCheckIfPasswordSeemsGood (const char *PlainPassword) { extern const char *Txt_The_new_password_must_be_at_least_X_characters; extern const char *Txt_The_new_password_can_not_contain_spaces; extern const char *Txt_The_new_password_can_not_consist_only_of_digits; unsigned LengthPassword = strlen (PlainPassword),i; bool ItsANumber; /***** Check length of password *****/ if (LengthPassword < Pwd_MIN_LENGTH_PLAIN_PASSWORD) // PlainPassword too short { sprintf (Gbl.Message,Txt_The_new_password_must_be_at_least_X_characters, Pwd_MIN_LENGTH_PLAIN_PASSWORD); return false; } /***** Check spaces in password *****/ if (strchr (PlainPassword,(int) ' ') != NULL) // PlainPassword with spaces { strcpy (Gbl.Message,Txt_The_new_password_can_not_contain_spaces); return false; } /***** Check if password is a number *****/ for (i = 0, ItsANumber = true; i < LengthPassword && ItsANumber; i++) if (PlainPassword[i] < '0' || PlainPassword[i] > '9') ItsANumber = false; if (ItsANumber) { strcpy (Gbl.Message,Txt_The_new_password_can_not_consist_only_of_digits); return false; } return true; } /*****************************************************************************/ /********************** Show form for changing my password *******************/ /*****************************************************************************/ void Pwd_ShowFormChgPwd (void) { extern const char *The_ClassFormul[The_NUM_THEMES]; extern const char *Txt_Before_going_to_any_other_option_you_must_create_your_password; extern const char *Txt_Your_password_is_not_secure_enough; extern const char *Txt_Your_password_must_be_at_least_X_characters_and_can_not_contain_spaces_; extern const char *Txt_Password; extern const char *Txt_Current_password; extern const char *Txt_Change_password; extern const char *Txt_Set_password; bool IHaveAPasswordInDB = (bool) Gbl.Usrs.Me.UsrDat.Password[0]; /***** Help message *****/ if (!IHaveAPasswordInDB) // If I don't have a password in database... Lay_ShowAlert (Lay_WARNING,Txt_Before_going_to_any_other_option_you_must_create_your_password); else if (Gbl.Usrs.Me.LoginPlainPassword[0]) { if (!Pwd_FastCheckIfPasswordSeemsGood (Gbl.Usrs.Me.LoginPlainPassword)) Lay_ShowAlert (Lay_WARNING,Txt_Your_password_is_not_secure_enough); } /***** Start form *****/ Act_FormStart (ActChgPwd); /***** Start table *****/ Lay_StartRoundFrameTable10 (NULL,2,Txt_Password); /* Current password */ if (IHaveAPasswordInDB) // If I have a password in database... fprintf (Gbl.F.Out,"" "" "%s: " "" "" "" "" "", The_ClassFormul[Gbl.Prefs.Theme], Txt_Current_password, Pwd_MAX_LENGTH_PLAIN_PASSWORD); /* Help message */ fprintf (Gbl.F.Out,"" ""); sprintf (Gbl.Message,Txt_Your_password_must_be_at_least_X_characters_and_can_not_contain_spaces_, Pwd_MIN_LENGTH_PLAIN_PASSWORD); Lay_ShowAlert (Lay_INFO,Gbl.Message); fprintf (Gbl.F.Out,"" ""); /* New password */ Pwd_PutFormToGetNewPasswordTwice (); /***** Send button and end form *****/ fprintf (Gbl.F.Out,"" ""); Lay_PutConfirmButton (IHaveAPasswordInDB ? Txt_Change_password : Txt_Set_password); fprintf (Gbl.F.Out,"" ""); Lay_EndRoundFrameTable10 (); Act_FormEnd (); } /*****************************************************************************/ /**************** Put form to request the new password twice *****************/ /*****************************************************************************/ void Pwd_PutFormToGetNewPasswordTwice (void) { extern const char *The_ClassFormul[The_NUM_THEMES]; extern const char *Txt_New_password; extern const char *Txt_Password; extern const char *Txt_HELP_password; extern const char *Txt_Retype_new_password; extern const char *Txt_Retype_password; sprintf (Gbl.Message,Txt_HELP_password,Pwd_MIN_LENGTH_PLAIN_PASSWORD); fprintf (Gbl.F.Out,"" "" "%s: " "" "" "" "" "" "" "" "%s: " "" "" "" "" "", The_ClassFormul[Gbl.Prefs.Theme], Gbl.Usrs.Me.Logged? Txt_New_password : // Changing my password Txt_Password, // Creating new account Pwd_MAX_LENGTH_PLAIN_PASSWORD, Gbl.Message, The_ClassFormul[Gbl.Prefs.Theme], Gbl.Usrs.Me.Logged ? Txt_Retype_new_password : // Changing my password Txt_Retype_password, // Creating new account Pwd_MAX_LENGTH_PLAIN_PASSWORD, Gbl.Message); } /*****************************************************************************/ /********** Show form to the change of password of another user **************/ /*****************************************************************************/ void Pwd_ShowFormOthPwd (void) { extern const char *The_ClassFormul[The_NUM_THEMES]; extern const char *Txt_Changing_the_password_for_the_following_user; extern const char *Txt_Save; extern const char *Txt_User_not_found_or_you_do_not_have_permission_; /***** Get user whose password must be changed *****/ if (Usr_GetParamOtherUsrCodEncryptedAndGetUsrData ()) { if (Pwd_CheckIfICanChangeOtherUsrPassword (Gbl.Usrs.Other.UsrDat.UsrCod)) { /***** Information message *****/ Lay_ShowAlert (Lay_INFO,Txt_Changing_the_password_for_the_following_user); /***** Show user's record *****/ fprintf (Gbl.F.Out,"" "" "" ""); /***** Form to change password *****/ /* Start form */ Act_FormStart (ActChgPwdOthUsr); Usr_PutParamOtherUsrCodEncrypted (); /* New password */ Pwd_PutFormToGetNewPasswordTwice (); fprintf (Gbl.F.Out,"
"); Rec_ShowSharedUsrRecord (Rec_RECORD_LIST,&Gbl.Usrs.Other.UsrDat); fprintf (Gbl.F.Out,"
"); /* End form */ Lay_PutConfirmButton (Txt_Save); Act_FormEnd (); } else Lay_ShowAlert (Lay_WARNING,Txt_User_not_found_or_you_do_not_have_permission_); } else // User not found Lay_ShowAlert (Lay_WARNING,Txt_User_not_found_or_you_do_not_have_permission_); } /*****************************************************************************/ /********* Put a link to the action used to change user's password ***********/ /*****************************************************************************/ void Pwd_PutLinkToChangeMyPassword (void) { extern const char *Txt_Change_password; /***** Link for changing the password *****/ Act_PutContextualLink (ActFrmChgMyPwd,NULL,"key",Txt_Change_password); } /*****************************************************************************/ /********* Put a link to the action used to change user's password ***********/ /*****************************************************************************/ void Pwd_PutLinkToChangeOtherUsrPassword (void) { extern const char *Txt_Change_password; /***** Link for changing the password *****/ if (Gbl.Usrs.Other.UsrDat.UsrCod == Gbl.Usrs.Me.UsrDat.UsrCod) // It's me Pwd_PutLinkToChangeMyPassword (); else // Not me Act_PutContextualLink (ActFrmPwdOthUsr,Usr_PutParamOtherUsrCodEncrypted, "key",Txt_Change_password); } /*****************************************************************************/ /************ Check if I can change th password of another user **************/ /*****************************************************************************/ bool Pwd_CheckIfICanChangeOtherUsrPassword (long UsrCod) { if (UsrCod == Gbl.Usrs.Me.UsrDat.UsrCod) // It's me return true; /* Check if I have permission to change user's password */ switch (Gbl.Usrs.Me.LoggedRole) { case Rol_DEG_ADM: /* If I am an administrator of current degree, I only can change the password of users from current degree */ return Usr_CheckIfUsrBelongsToDeg (UsrCod,Gbl.CurrentDeg.Deg.DegCod); case Rol_SYS_ADM: return true; default: return false; } } /*****************************************************************************/ /***************** Ask for confirmation on dangerous actions *****************/ /*****************************************************************************/ void Pwd_AskForConfirmationOnDangerousAction (void) { extern const char *The_ClassFormul[The_NUM_THEMES]; extern const char *Txt_I_understand_that_this_action_may_have_serious_consequences_and_can_not_be_undone; extern const char *Txt_For_security_enter_your_password; fprintf (Gbl.F.Out,"
" "" "%s
" "%s: " "" "
", The_ClassFormul[Gbl.Prefs.Theme], Txt_I_understand_that_this_action_may_have_serious_consequences_and_can_not_be_undone, The_ClassFormul[Gbl.Prefs.Theme], Txt_For_security_enter_your_password, Pwd_MAX_LENGTH_PLAIN_PASSWORD); } /*****************************************************************************/ /******************** Get confirmation on dangerous actions ******************/ /*****************************************************************************/ // Returns true if consent have been checked and my password is correct bool Pwd_GetConfirmationOnDangerousAction (void) { extern const char *Txt_You_have_not_confirmed_the_action; extern const char *Txt_You_have_not_entered_your_password_correctly; char YN[1+1]; char PlainPassword[Pwd_MAX_LENGTH_PLAIN_PASSWORD+1]; char EncryptedPassword[Cry_LENGTH_ENCRYPTED_STR_SHA512_BASE64+1]; /***** Get if consent has been done *****/ Par_GetParToText ("Consent",YN,1); if (Str_ConvertToUpperLetter (YN[0]) != 'Y') { Lay_ShowAlert (Lay_WARNING,Txt_You_have_not_confirmed_the_action); return false; } /***** Get my password *****/ /* Get plain password from form */ Par_GetParToText ("OthUsrPwd",PlainPassword,Pwd_MAX_LENGTH_PLAIN_PASSWORD); /* Encrypt password */ Cry_EncryptSHA512Base64 (PlainPassword,EncryptedPassword); /* Compare passwords */ if (strcmp (Gbl.Usrs.Me.LoginEncryptedPassword,EncryptedPassword)) { Lay_ShowAlert (Lay_WARNING,Txt_You_have_not_entered_your_password_correctly); return false; } return true; }