CASA/c_micasad/common/SessionManager.cs
2006-01-31 22:01:47 +00:00

375 lines
13 KiB
C#

/***********************************************************************
*
* Copyright (C) 2005-2006 Novell, Inc. Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; version 2.1
* of the License.
*
* This library 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
* Library Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, Novell, Inc.
*
* To contact Novell about this file by physical or electronic mail,
* you may find current contact information at www.novell.com.
*
***********************************************************************/
using System;
using System.Collections;
using System.Threading;
using System.IO;
using sscs.cache;
using sscs.common;
using sscs.constants;
using System.Diagnostics;
namespace sscs.common
{
class SessionManager
{
private static readonly SessionManager sessionManager = new SessionManager();
private static Mutex mutex = new Mutex();
private static Hashtable sessionTable = new Hashtable();
private static Thread tJanitor = null;
private static int JANITOR_SLEEP_TIME = 1000*60*5; // 5 minutes
private SessionManager()
{
#if LINUX
if (tJanitor == null)
{
tJanitor = new Thread(new ThreadStart(CleanUpSessionsThread));
tJanitor.Start();
}
#endif
}
~SessionManager()
{
if (tJanitor != null)
{
tJanitor.Abort();
tJanitor.Join();
}
mutex.Close();
}
internal static SessionManager GetSessionManager
{
get
{
return sessionManager;
}
}
internal static SecretStore CreateUserSession(UserIdentifier userId)
{
CSSSLogger.ExecutionTrace(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
SecretStore ss;
userId.PrintIdentifier();
try
{
ss = GetUserSecretStore(userId);
ss.IncrRefCount();
ss.CreateTime = DateTime.Now;
return ss;
}
catch(UserNotInSessionException e)
{
// Would create either windows/unix user
// depending on the platform.
User user = User.CreateUser(userId);
mutex.WaitOne();
sessionTable.Add(userId,user);
mutex.ReleaseMutex();
ss = user.GetSecretStore();
ss.IncrRefCount();
ss.CreateTime = DateTime.Now;
return ss;
}
}
internal static bool RemoveUserSession(UserIdentifier userId, bool destroySession)
{
CSSSLogger.ExecutionTrace(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
try
{
mutex.WaitOne();
SecretStore ss = GetUserSecretStore(userId);
ss.DecrRefCount();
// We must keep the cache alive, and destroy it on
// a logout event
//if( 0 == ss.refCount )
if (destroySession)
{
CSSSLogger.DbgLog("Removing the user session of " + userId.GetUID());
ss.CommitStore();
sessionTable.Remove(userId);
}
mutex.ReleaseMutex();
return true;
}
catch(Exception e)
{
CSSSLogger.ExpLog(e.ToString());
}
return false;
}
internal static bool CheckIfUserSessionExists(UserIdentifier userId)
{
CSSSLogger.ExecutionTrace(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
mutex.WaitOne();
if( sessionTable.ContainsKey(userId) )
{
mutex.ReleaseMutex();
return true;
}
else
{
mutex.ReleaseMutex();
return false;
}
}
internal static SecretStore GetUserSecretStore(UserIdentifier userId)
{
CSSSLogger.ExecutionTrace(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
userId.PrintIdentifier();
ListActiveUserSessions();
mutex.WaitOne();
if( sessionTable.ContainsKey(userId) )
{
User user = (User)sessionTable[userId];
SecretStore ss = user.GetSecretStore();
// start persistent if not going yet
if (!ss.IsStorePersistent())
{
string sDesktopPWD = ss.GetDesktopPasswd();
if (sDesktopPWD != null)
ss.StartPersistenceByDesktopPasswd(sDesktopPWD);
}
mutex.ReleaseMutex();
return ss;
}
else
{
mutex.ReleaseMutex();
throw new UserNotInSessionException(userId);
}
}
internal static DateTime GetSessionCreateTime(UserIdentifier userId)
{
CSSSLogger.ExecutionTrace(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
mutex.WaitOne();
if( sessionTable.ContainsKey(userId) )
{
User user = (User)sessionTable[userId];
SecretStore ss = user.GetSecretStore();
mutex.ReleaseMutex();
return ss.CreateTime;
}
else
{
mutex.ReleaseMutex();
throw new UserNotInSessionException(userId);
}
}
internal static void ListActiveUserSessions()
{
CSSSLogger.ExecutionTrace(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
mutex.WaitOne();
IDictionaryEnumerator etor = sessionTable.GetEnumerator();
int i = 0;
while(etor.MoveNext())
{
i++;
/*
CSSSLogger.DbgLog("Listing Active User Sessions");
Console.WriteLine(etor.Key);
Console.WriteLine((((SecretStore)(etor.Value)).secretStoreName + ":" + ((SecretStore)(etor.Value)).refCount);
*/
}
mutex.ReleaseMutex();
}
private static void CleanUpSessionsThread()
{
CSSSLogger.ExecutionTrace(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
try
{
while (true)
{
// enumerate users in the session
IEnumerator etor;
ICollection keys = sessionTable.Keys;
if (keys != null)
{
etor = keys.GetEnumerator();
while(etor.MoveNext())
{
UserIdentifier userIdentifier = (UserIdentifier)etor.Current;
// check if this user still has
// processes running
if(CheckAndDestroySession(userIdentifier,false))
{
/* If at least 1 session was removed,
* the etor must be
* re-initiated, else
* Invalidoperationexception will be
* thrown.
*/
keys = sessionTable.Keys;
if( null == keys )
break;
else
{
etor = keys.GetEnumerator();
}
}
}//while etor.MoveNext ends here.
}
Thread.Sleep(JANITOR_SLEEP_TIME);
} //while true ends here.
}
catch(ThreadAbortException e)
{
CSSSLogger.DbgLog("Janitor thread is going down.");
}
}//Method ends here.
/* As the pam module does a seteuid(), when is ps is
* execed it would appear as if the user owns the process.
* Hence, if this method is called from CloseSecretStore
* verb ( that would have been initiated from the pam
* module with ssFlags = 1), then if number of processes
* is one, then delete the session.
*/
internal static bool CheckAndDestroySession(UserIdentifier userID, bool calledFromClose)
{
CSSSLogger.ExecutionTrace(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
int iUID = userID.GetUID();
bool retVal = false;
Process myProcess = null;
StreamReader myStreamReader = null;
if (iUID != -1)
{
// make the 'ps h U UID' call
try
{
myProcess = new Process();
ProcessStartInfo myProcessStartInfo = new ProcessStartInfo("ps" );
myProcessStartInfo.Arguments = "h U " + iUID.ToString();
myProcessStartInfo.UseShellExecute = false;
myProcessStartInfo.RedirectStandardOutput = true;
myProcess.StartInfo = myProcessStartInfo;
myProcess.Start();
myProcess.WaitForExit();
myStreamReader = myProcess.StandardOutput;
// Read the standard output of the spawned process.
string myString = myStreamReader.ReadLine();
int numProcs = 0;
while( myString != null)
{
if(numProcs > 1)
break;
numProcs++;
myString = myStreamReader.ReadLine();
}
do
{
/* If this has been called from
* CloseSecretStore verb,
* verb, the session must be deleted.
*/
if( calledFromClose )
{
RemoveUserSession(userID, true);
retVal = true;
break;
}
/* If the session was created during login,
* and the janitor thread starts processing
* before user login is completed, we need
* maintain the user session (say for 5 mts).
*/
if( (numProcs == 0) && (CheckIfLoginTimeSession(userID)) )
{
retVal = false;
break;
}
/* If the user does not own any processes and
* if this method has not been called from
* CloseSecretStore verb, it implies that a user
* background process, which existed during user
* logout has died now.
* So, clean the user session.
*/
if ( (numProcs == 0) && (!calledFromClose) )
{
RemoveUserSession(userID, true);
retVal = true;
break;
}
}while(false);
/*
myProcess.Close();
myStreamReader.Close();
*/
}
catch (Exception e)
{
CSSSLogger.DbgLog(e.ToString());
}
finally
{
if( myProcess != null )
myProcess.Close();
if( myStreamReader != null )
myStreamReader.Close();
}
}
return retVal;
}
internal static bool CheckIfLoginTimeSession(UserIdentifier userId)
{
if( ((TimeSpan)(DateTime.Now - GetSessionCreateTime(userId))).TotalMinutes < 3 )
{
return true;
}
else
return false;
}
}
}