swad-core/swad_password.c

935 lines
34 KiB
C

// 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 <http://www.gnu.org/licenses/>.
*/
/*****************************************************************************/
/********************************* Headers ***********************************/
/*****************************************************************************/
#define _GNU_SOURCE // For asprintf
#include <stdio.h> // For asprintf
#include <stdlib.h> // For system, getenv, etc.
#include <string.h> // For string functions
#include <sys/wait.h> // For the macro WEXITSTATUS
#include <unistd.h> // For unlink
#include "swad_box.h"
#include "swad_database.h"
#include "swad_enrolment.h"
#include "swad_form.h"
#include "swad_global.h"
#include "swad_ID.h"
#include "swad_password.h"
#include "swad_parameter.h"
#include "swad_table.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;
/***** Start form *****/
Frm_StartForm (ActSndNewPwd);
/***** Start box *****/
Box_StartBox (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,"<label class=\"%s\">"
"%s:&nbsp;"
"<input type=\"text\" name=\"UsrId\""
" size=\"8\" maxlength=\"%u\" value=\"%s\""
" required=\"required\" />"
"</label>",
The_ClassFormInBox[Gbl.Prefs.Theme],Txt_nick_email_or_ID,
Cns_MAX_CHARS_EMAIL_ADDRESS,Gbl.Usrs.Me.UsrIdLogin);
/***** Send button and end box *****/
Box_EndBoxWithButton (Btn_CONFIRM_BUTTON,Txt_Get_a_new_password);
/***** End form *****/
Frm_EndForm ();
}
/*****************************************************************************/
/*********************** Send a new password by email ************************/
/*****************************************************************************/
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_;
struct ListUsrCods ListUsrCods;
unsigned NumUsr;
char NewRandomPlainPassword[Pwd_MAX_BYTES_PLAIN_PASSWORD + 1];
int ReturnCode;
char ErrorTxt[256];
/***** Check if user's ID or nickname is not empty *****/
if (!Gbl.Usrs.Me.UsrIdLogin[0])
{
Ale_ShowAlert (Ale_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.Me.UsrDat.UsrCod;
}
}
else if (Mai_CheckIfEmailIsValid (Gbl.Usrs.Me.UsrIdLogin)) // 2: It's an email
{
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.Me.UsrDat.UsrCod;
}
}
else // 3: It's not a nickname nor email
{
// Users' IDs are always stored internally in capitals and without leading zeros
Str_RemoveLeadingZeros (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
Str_Copy (Gbl.Usrs.Me.UsrDat.IDs.List[0].ID,Gbl.Usrs.Me.UsrIdLogin,
ID_MAX_BYTES_USR_ID);
Str_ConvertToUpperText (Gbl.Usrs.Me.UsrDat.IDs.List[0].ID);
/* 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 email when user exists *****/
for (NumUsr = 0;
NumUsr < ListUsrCods.NumUsrs;
NumUsr++)
{
Gbl.Usrs.Me.UsrDat.UsrCod = ListUsrCods.Lst[NumUsr];
Usr_GetUsrDataFromUsrCod (&Gbl.Usrs.Me.UsrDat,Usr_DONT_GET_PREFS); // Get my data
if (Gbl.Usrs.Me.UsrDat.Email[0])
switch ((ReturnCode = Pwd_SendNewPasswordByEmail (NewRandomPlainPassword)))
{
case 0: // Message sent successfully
Pwd_SetMyPendingPassword (NewRandomPlainPassword);
break;
case 1:
Lay_ShowErrorAndExit (Txt_There_was_a_problem_sending_an_email_automatically);
break;
default:
snprintf (ErrorTxt,sizeof (ErrorTxt),
"Internal error: an email message has not been sent successfully."
" Error code returned by the script: %d",
ReturnCode);
Lay_ShowErrorAndExit (ErrorTxt);
break;
}
}
/***** Free list of users' codes *****/
Usr_FreeListUsrCods (&ListUsrCods);
/***** Help message *****/
Ale_ShowAlert (Ale_INFO,Txt_If_you_have_written_your_ID_nickname_or_email_correctly_);
/**** Show forms to login / create account again *****/
Usr_WriteLandingPage ();
}
/*****************************************************************************/
/*********************** Send a new password by email ************************/
/*****************************************************************************/
// Gbl.Usrs.Me.UsrDat must be filled
// Return code returned by command
int Pwd_SendNewPasswordByEmail (char NewRandomPlainPassword[Pwd_MAX_BYTES_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[1 + Lan_NUM_LANGUAGES];
char Command[2048 +
Cfg_MAX_BYTES_SMTP_PASSWORD +
Cns_MAX_BYTES_EMAIL_ADDRESS +
PATH_MAX]; // Command to execute for sending an email
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_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 email *****/
snprintf (Command,sizeof (Command),
"%s \"%s\" \"%s\" \"%s\" \"%s\" \"%s\" \"[%s] %s\" \"%s\"",
Cfg_COMMAND_SEND_AUTOMATIC_EMAIL,
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 email.");
/***** 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_BYTES_PLAIN_PASSWORD + 1])
{
Str_CreateRandomAlphanumStr (PlainPassword,Pwd_MIN_CHARS_PLAIN_PASSWORD);
}
/*****************************************************************************/
/*************************** Set my pending password *************************/
/*****************************************************************************/
void Pwd_SetMyPendingPassword (char PlainPassword[Pwd_MAX_BYTES_PLAIN_PASSWORD + 1])
{
/***** Encrypt my pending password *****/
Cry_EncryptSHA512Base64 (PlainPassword,Gbl.Usrs.Me.PendingPassword);
/***** Remove expired pending passwords from database *****/
DB_QueryDELETE ("can not remove expired pending passwords",
"DELETE LOW_PRIORITY FROM pending_passwd"
" WHERE DateAndTime<FROM_UNIXTIME(UNIX_TIMESTAMP()-%lu)",
Cfg_TIME_TO_DELETE_OLD_PENDING_PASSWORDS);
/***** Update my current password in database *****/
DB_QueryREPLACE ("can not create pending password",
"REPLACE INTO pending_passwd"
" (UsrCod,PendingPassword,DateAndTime)"
" VALUES"
" (%ld,'%s',NOW())",
Gbl.Usrs.Me.UsrDat.UsrCod,Gbl.Usrs.Me.PendingPassword);
}
/*****************************************************************************/
/************************ Check if a password is good ************************/
/*****************************************************************************/
bool Pwd_SlowCheckIfPasswordIsGood (const char *PlainPassword,
const char *EncryptedPassword,
long UsrCod)
{
extern const char *Txt_The_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
{
Ale_CreateAlert (Ale_WARNING,Pwd_PASSWORD_SECTION_ID,
Txt_The_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)
{
Ale_CreateAlert (Ale_WARNING,Pwd_PASSWORD_SECTION_ID,
Txt_The_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)
{
bool Found;
/***** Get if password is found in user's ID from database *****/
Found = (DB_QueryCOUNT ("can not check if a password matches a user's ID",
"SELECT COUNT(*) FROM usr_IDs"
" WHERE UsrID='%s'",
PlainPassword) != 0);
/***** Get if password is found in first name or surnames of anybody, from database *****/
if (!Found)
Found = (DB_QueryCOUNT ("can not check if a password matches"
" a first name or a surname",
"SELECT COUNT(*) FROM usr_data"
" WHERE FirstName='%s'"
" OR Surname1='%s'"
" OR Surname2='%s'",
PlainPassword,PlainPassword,PlainPassword) != 0);
return Found;
}
/*****************************************************************************/
/************** Get the number of users who use yet a password ***************/
/*****************************************************************************/
static unsigned Pwd_GetNumOtherUsrsWhoUseThisPassword (const char *EncryptedPassword,long UsrCod)
{
unsigned NumUsrs;
char *SubQuery;
/***** Build subquery *****/
if (UsrCod > 0)
{
if (asprintf (&SubQuery," AND UsrCod<>%ld",UsrCod) < 0)
Lay_NotEnoughMemoryExit ();
}
else
SubQuery = "";
/***** Get number of other users who use a password from database *****/
NumUsrs =
(unsigned) DB_QueryCOUNT ("can not check if a password is trivial",
"SELECT COUNT(*) FROM usr_data"
" WHERE Password='%s'%s",
EncryptedPassword,SubQuery);
/***** Free subquery *****/
if (UsrCod > 0)
free ((void *) SubQuery);
return NumUsrs;
}
/*****************************************************************************/
/********************** Check if a password seems good ***********************/
/*****************************************************************************/
bool Pwd_FastCheckIfPasswordSeemsGood (const char *PlainPassword)
{
extern const char *Txt_The_password_must_be_at_least_X_characters;
extern const char *Txt_The_password_can_not_contain_spaces;
extern const char *Txt_The_password_can_not_consist_only_of_digits;
unsigned LengthPassword = strlen (PlainPassword),i;
bool ItsANumber;
/***** Check length of password *****/
if (LengthPassword < Pwd_MIN_BYTES_PLAIN_PASSWORD) // PlainPassword too short
{
Ale_CreateAlert (Ale_WARNING,Pwd_PASSWORD_SECTION_ID,
Txt_The_password_must_be_at_least_X_characters,
Pwd_MIN_CHARS_PLAIN_PASSWORD);
return false;
}
/***** Check spaces in password *****/
if (strchr (PlainPassword,(int) ' ') != NULL) // PlainPassword with spaces
{
Ale_CreateAlert (Ale_WARNING,Pwd_PASSWORD_SECTION_ID,
Txt_The_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)
{
Ale_CreateAlert (Ale_WARNING,Pwd_PASSWORD_SECTION_ID,
Txt_The_password_can_not_consist_only_of_digits);
return false;
}
return true;
}
/*****************************************************************************/
/********************** Show form for changing my password *******************/
/*****************************************************************************/
void Pwd_ShowFormChgMyPwd (void)
{
extern const char *Hlp_PROFILE_Password;
extern const char *The_ClassFormInBox[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;
char StrRecordWidth[10 + 1];
bool IHaveAPasswordInDB = (bool) Gbl.Usrs.Me.UsrDat.Password[0];
/***** Start section *****/
Lay_StartSection (Pwd_PASSWORD_SECTION_ID);
/***** Start form *****/
Frm_StartFormAnchor (ActChgMyPwd,Pwd_PASSWORD_SECTION_ID);
/***** Start box *****/
snprintf (StrRecordWidth,sizeof (StrRecordWidth),
"%upx",
Rec_RECORD_WIDTH);
Box_StartBox (StrRecordWidth,Txt_Password,NULL,
Hlp_PROFILE_Password,Box_NOT_CLOSABLE);
/***** Show possible alerts *****/
Ale_ShowAlerts (Pwd_PASSWORD_SECTION_ID);
/***** Help message *****/
if (!IHaveAPasswordInDB) // If I don't have a password in database...
Ale_ShowAlert (Ale_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))
Ale_ShowAlert (Ale_WARNING,Txt_Your_password_is_not_secure_enough);
}
/***** Start table *****/
Tbl_StartTableWide (2);
/***** Current password *****/
if (IHaveAPasswordInDB) // If I have a password in database...
fprintf (Gbl.F.Out,"<tr>"
"<td class=\"REC_C1_BOT RIGHT_MIDDLE\">"
"<label for=\"UsrPwd\" class=\"%s\">%s:</label>"
"</td>"
"<td class=\"REC_C2_BOT LEFT_MIDDLE\">"
"<input type=\"password\""
" id=\"UsrPwd\" name=\"UsrPwd\""
" size=\"18\" maxlength=\"%u\""
" autocomplete=\"off\" required=\"required\" />"
"</td>"
"</tr>",
The_ClassFormInBox[Gbl.Prefs.Theme],
Txt_Current_password,
Pwd_MAX_CHARS_PLAIN_PASSWORD);
/***** Help message *****/
fprintf (Gbl.F.Out,"<tr>"
"<td colspan=\"2\">");
Ale_ShowAlert (Ale_INFO,Txt_Your_password_must_be_at_least_X_characters_and_can_not_contain_spaces_,
Pwd_MIN_CHARS_PLAIN_PASSWORD);
fprintf (Gbl.F.Out,"</td>"
"</tr>");
/***** New password *****/
Pwd_PutFormToGetNewPasswordTwice ();
/***** End table, send button and end box *****/
Box_EndBoxTableWithButton (Btn_CONFIRM_BUTTON,
IHaveAPasswordInDB ? Txt_Change_password :
Txt_Set_password);
/***** End form *****/
Frm_EndForm ();
/***** End section *****/
Lay_EndSection ();
}
/*****************************************************************************/
/**************** Put form to request the new password once ******************/
/*****************************************************************************/
void Pwd_PutFormToGetNewPasswordOnce (void)
{
extern const char *The_ClassFormInBox[The_NUM_THEMES];
extern const char *Txt_Password;
extern const char *Txt_HELP_password;
/***** Start form element ****/
fprintf (Gbl.F.Out,"<tr>"
"<td class=\"RIGHT_MIDDLE\">"
"<label for=\"Passwd\" class=\"%s\">%s:</label>"
"</td>"
"<td class=\"LEFT_MIDDLE\">"
"<input type=\"password\" id=\"Passwd\" name=\"Paswd\""
" size=\"18\" maxlength=\"%u\" placeholder=\"",
The_ClassFormInBox[Gbl.Prefs.Theme],
Txt_Password,
Pwd_MAX_CHARS_PLAIN_PASSWORD);
/***** Placeholder *****/
fprintf (Gbl.F.Out,Txt_HELP_password,
Pwd_MIN_CHARS_PLAIN_PASSWORD);
/***** End form element ****/
fprintf (Gbl.F.Out,"\""
" required=\"required\" />"
"</td>"
"</tr>");
}
/*****************************************************************************/
/**************** Put form to request the new password twice *****************/
/*****************************************************************************/
void Pwd_PutFormToGetNewPasswordTwice (void)
{
extern const char *The_ClassFormInBox[The_NUM_THEMES];
extern const char *Txt_New_password;
extern const char *Txt_HELP_password;
extern const char *Txt_Retype_new_password;
/***** 1st password *****/
/* Start form element */
fprintf (Gbl.F.Out,"<tr>"
"<td class=\"REC_C1_BOT RIGHT_MIDDLE\">"
"<label for=\"Paswd1\" class=\"%s\">%s:</label>"
"</td>"
"<td class=\"REC_C2_BOT LEFT_MIDDLE\">"
"<input type=\"password\" id=\"Paswd1\" name=\"Paswd1\""
" size=\"18\" maxlength=\"%u\""
" placeholder=\"",
The_ClassFormInBox[Gbl.Prefs.Theme],
Txt_New_password,
Pwd_MAX_CHARS_PLAIN_PASSWORD);
/* Placeholder */
fprintf (Gbl.F.Out,Txt_HELP_password,
Pwd_MIN_CHARS_PLAIN_PASSWORD);
/* End form element */
fprintf (Gbl.F.Out,"\" required=\"required\" />"
"</td>"
"</tr>");
/***** 2nd password *****/
/* Start form element */
fprintf (Gbl.F.Out,"<tr>"
"<td class=\"REC_C1_BOT RIGHT_MIDDLE\">"
"<label for=\"Paswd2\" class=\"%s\">%s:</label>"
"</td>"
"<td class=\"REC_C2_BOT LEFT_MIDDLE\">"
"<input type=\"password\" id=\"Paswd2\" name=\"Paswd2\""
" size=\"18\" maxlength=\"%u\""
" placeholder=\"",
The_ClassFormInBox[Gbl.Prefs.Theme],
Txt_Retype_new_password,
Pwd_MAX_CHARS_PLAIN_PASSWORD);
/* Placeholder */
fprintf (Gbl.F.Out,Txt_HELP_password,
Pwd_MIN_CHARS_PLAIN_PASSWORD);
/* End form element */
fprintf (Gbl.F.Out,"\" required=\"required\" />"
"</td>"
"</tr>");
}
/*****************************************************************************/
/********** Show form to the change of password of another user **************/
/*****************************************************************************/
void Pwd_ShowFormChgOtherUsrPwd (void)
{
extern const char *Txt_Password;
extern const char *Txt_Change_password;
Act_Action_t NextAction;
/***** Start box *****/
Box_StartBox (NULL,Txt_Password,NULL,
NULL,Box_NOT_CLOSABLE);
/***** Start section *****/
Lay_StartSection (Pwd_PASSWORD_SECTION_ID);
/***** Show possible alerts *****/
Ale_ShowAlerts (Pwd_PASSWORD_SECTION_ID);
/***** Form to change password *****/
/* Start form */
switch (Gbl.Usrs.Other.UsrDat.Roles.InCurrentCrs.Role)
{
case Rol_STD:
NextAction = ActChgPwdStd;
break;
case Rol_NET:
case Rol_TCH:
NextAction = ActChgPwdTch;
break;
default: // Guest, user or admin
NextAction = ActChgPwdOth;
break;
}
Frm_StartFormAnchor (NextAction,Pwd_PASSWORD_SECTION_ID);
Usr_PutParamOtherUsrCodEncrypted ();
/* New password */
Tbl_StartTableWide (2);
Pwd_PutFormToGetNewPasswordTwice ();
Tbl_EndTable ();
/* End form */
Btn_PutConfirmButton (Txt_Change_password);
Frm_EndForm ();
/***** End box *****/
Box_EndBox ();
/***** End section *****/
Lay_EndSection ();
}
/*****************************************************************************/
/***************** Ask for confirmation on dangerous actions *****************/
/*****************************************************************************/
void Pwd_AskForConfirmationOnDangerousAction (void)
{
extern const char *The_ClassFormInBox[The_NUM_THEMES];
extern const char *Txt_I_understand_that_this_action_can_not_be_undone;
extern const char *Txt_For_security_enter_your_password;
fprintf (Gbl.F.Out,"<div class=\"CENTER_MIDDLE\" style=\"margin:12px;\">"
"<label class=\"%s\">"
"<input type=\"checkbox\" name=\"Consent\" value=\"Y\" />"
"%s"
"</label>"
"<br />"
"<label class=\"%s\">"
"%s:&nbsp;"
"<input type=\"password\" name=\"OthUsrPwd\""
" size=\"16\" maxlength=\"%u\""
" autocomplete=\"off\" required=\"required\" />"
"</label>"
"</div>",
The_ClassFormInBox[Gbl.Prefs.Theme],
Txt_I_understand_that_this_action_can_not_be_undone,
The_ClassFormInBox[Gbl.Prefs.Theme],
Txt_For_security_enter_your_password,
Pwd_MAX_CHARS_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 PlainPassword[Pwd_MAX_BYTES_PLAIN_PASSWORD + 1];
char EncryptedPassword[Pwd_BYTES_ENCRYPTED_PASSWORD + 1];
/***** Get if consent has been done *****/
if (!Par_GetParToBool ("Consent"))
{
Ale_ShowAlert (Ale_WARNING,Txt_You_have_not_confirmed_the_action);
return false;
}
/***** Get my password *****/
/* Get plain password from form */
Par_GetParToText ("OthUsrPwd",PlainPassword,Pwd_MAX_BYTES_PLAIN_PASSWORD);
/* Encrypt password */
Cry_EncryptSHA512Base64 (PlainPassword,EncryptedPassword);
/* Compare passwords */
if (strcmp (Gbl.Usrs.Me.LoginEncryptedPassword,EncryptedPassword))
{
Ale_ShowAlert (Ale_WARNING,Txt_You_have_not_entered_your_password_correctly);
return false;
}
return true;
}