// 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,"