// swad_session.c: sessions /* 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 ********************************/ /*****************************************************************************/ #include // For NULL #include // To access MySQL databases #include // For sprintf #include // For malloc and free #include // For string functions #include "swad_connected.h" #include "swad_database.h" #include "swad_global.h" #include "swad_parameter.h" #include "swad_timeline.h" /*****************************************************************************/ /**************************** Internal constants *****************************/ /*****************************************************************************/ /*****************************************************************************/ /************** External global variables from others modules ****************/ /*****************************************************************************/ extern struct Globals Gbl; /*****************************************************************************/ /***************************** Internal prototypes ***************************/ /*****************************************************************************/ static void Ses_RemoveSessionFromDB (void); static bool Ses_CheckIfHiddenParIsAlreadyInDB (Act_Action_t NextAction, const char *ParamName); /*****************************************************************************/ /************************** Get number of open sessions **********************/ /*****************************************************************************/ void Ses_GetNumSessions (void) { /***** Get the number of open sessions from database *****/ Gbl.Session.NumSessions = (unsigned) DB_GetNumRowsTable ("sessions"); Gbl.Usrs.Connected.TimeToRefreshInMs = (unsigned long) (Gbl.Session.NumSessions/Cfg_TIMES_PER_SECOND_REFRESH_CONNECTED) * 1000UL; if (Gbl.Usrs.Connected.TimeToRefreshInMs < Con_MIN_TIME_TO_REFRESH_CONNECTED_IN_MS) Gbl.Usrs.Connected.TimeToRefreshInMs = Con_MIN_TIME_TO_REFRESH_CONNECTED_IN_MS; else if (Gbl.Usrs.Connected.TimeToRefreshInMs > Con_MAX_TIME_TO_REFRESH_CONNECTED_IN_MS) Gbl.Usrs.Connected.TimeToRefreshInMs = Con_MAX_TIME_TO_REFRESH_CONNECTED_IN_MS; } /*****************************************************************************/ /*************************** Create a new session ****************************/ /*****************************************************************************/ void Ses_CreateSession (void) { /***** Create a unique name for the session *****/ Str_Copy (Gbl.Session.Id,Gbl.UniqueNameEncrypted, Cns_BYTES_SESSION_ID); /***** Check that session is not open *****/ if (Ses_CheckIfSessionExists (Gbl.Session.Id)) Lay_ShowErrorAndExit ("Can not create session."); /***** Add session to database *****/ Ses_InsertSessionInDB (); /***** Update time and course in connected list *****/ Con_UpdateMeInConnectedList (); /***** Update number of open sessions in order to show them properly *****/ Ses_GetNumSessions (); } /*****************************************************************************/ /*********** Check if the session already exists in the database *************/ /*****************************************************************************/ // Return true if session exists // Return false if session does not exist or error bool Ses_CheckIfSessionExists (const char *IdSes) { /***** Get if session already exists in database *****/ return (DB_QueryCOUNT ("can not check if a session already existed", "SELECT COUNT(*) FROM sessions" " WHERE SessionId='%s'", IdSes) != 0); } /*****************************************************************************/ /************************** Close current session ****************************/ /*****************************************************************************/ void Ses_CloseSession (void) { if (Gbl.Usrs.Me.Logged) { /***** Remove session from database *****/ Ses_RemoveSessionFromDB (); Gbl.Session.IsOpen = false; // Gbl.Session.HasBeenDisconnected = true; Gbl.Session.Id[0] = '\0'; /***** If there are no more sessions for current user ==> remove user from connected list *****/ Con_RemoveOldConnected (); Ses_RemoveHiddenParFromExpiredSessions (); /***** Now, user is not logged in *****/ Gbl.Usrs.Me.Role.LoggedBeforeCloseSession = Gbl.Usrs.Me.Role.Logged; Gbl.Usrs.Me.Logged = false; Gbl.Usrs.Me.IBelongToCurrentIns = false; Gbl.Usrs.Me.IBelongToCurrentCtr = false; Gbl.Usrs.Me.IBelongToCurrentDeg = false; Gbl.Usrs.Me.IBelongToCurrentCrs = false; Gbl.Usrs.Me.Role.Logged = Rol_UNK; // Don't uncomment this line. Don't change the role to unknown. Keep user's role in order to log the access Gbl.Usrs.Me.MyCrss.Filled = false; Gbl.Usrs.Me.MyCrss.Num = 0; /***** Update number of open sessions in order to show them properly *****/ Ses_GetNumSessions (); } } /*****************************************************************************/ /******************** Insert new session in the database *********************/ /*****************************************************************************/ void Ses_InsertSessionInDB (void) { /***** Insert session in the database *****/ if (Gbl.Search.WhatToSearch == Sch_SEARCH_UNKNOWN) Gbl.Search.WhatToSearch = Sch_WHAT_TO_SEARCH_DEFAULT; DB_QueryINSERT ("can not create session", "INSERT INTO sessions" " (SessionId,UsrCod,Password,Role," "CtyCod,InsCod,CtrCod,DegCod,CrsCod,LastTime,LastRefresh,WhatToSearch)" " VALUES" " ('%s',%ld,'%s',%u," "%ld,%ld,%ld,%ld,%ld,NOW(),NOW(),%u)", Gbl.Session.Id, Gbl.Usrs.Me.UsrDat.UsrCod, Gbl.Usrs.Me.UsrDat.Password, (unsigned) Gbl.Usrs.Me.Role.Logged, Gbl.Hierarchy.Cty.CtyCod, Gbl.Hierarchy.Ins.InsCod, Gbl.Hierarchy.Ctr.CtrCod, Gbl.Hierarchy.Deg.DegCod, Gbl.Hierarchy.Crs.CrsCod, Gbl.Search.WhatToSearch); } /*****************************************************************************/ /***************** Modify data of session in the database ********************/ /*****************************************************************************/ void Ses_UpdateSessionDataInDB (void) { /***** Update session in database *****/ DB_QueryUPDATE ("can not update session", "UPDATE sessions SET UsrCod=%ld,Password='%s',Role=%u," "CtyCod=%ld,InsCod=%ld,CtrCod=%ld,DegCod=%ld,CrsCod=%ld," "LastTime=NOW(),LastRefresh=NOW()" " WHERE SessionId='%s'", Gbl.Usrs.Me.UsrDat.UsrCod, Gbl.Usrs.Me.UsrDat.Password, (unsigned) Gbl.Usrs.Me.Role.Logged, Gbl.Hierarchy.Cty.CtyCod, Gbl.Hierarchy.Ins.InsCod, Gbl.Hierarchy.Ctr.CtrCod, Gbl.Hierarchy.Deg.DegCod, Gbl.Hierarchy.Crs.CrsCod, Gbl.Session.Id); } /*****************************************************************************/ /******************** Modify session last refresh in database ****************/ /*****************************************************************************/ void Ses_UpdateSessionLastRefreshInDB (void) { /***** Update session in database *****/ DB_QueryUPDATE ("can not update session", "UPDATE sessions SET LastRefresh=NOW() WHERE SessionId='%s'", Gbl.Session.Id); } /*****************************************************************************/ /********************** Remove session from the database *********************/ /*****************************************************************************/ static void Ses_RemoveSessionFromDB (void) { /***** Remove current session *****/ DB_QueryDELETE ("can not remove a session", "DELETE FROM sessions WHERE SessionId='%s'", Gbl.Session.Id); /***** Clear old unused social timelines in database *****/ // This is necessary to prevent the table growing and growing TL_ClearOldTimelinesDB (); } /*****************************************************************************/ /*************************** Remove expired sessions *************************/ /*****************************************************************************/ void Ses_RemoveExpiredSessions (void) { /***** Remove expired sessions *****/ /* A session expire when last click (LastTime) is too old, or (when there was at least one refresh (navigator supports AJAX) and last refresh is too old (browser probably was closed)) */ DB_QueryDELETE ("can not remove expired sessions", "DELETE LOW_PRIORITY FROM sessions WHERE" " LastTimeLastTime+INTERVAL 1 SECOND" " AND" " LastRefresh