378 lines
9.6 KiB
C#
378 lines
9.6 KiB
C#
/***********************************************************************
|
|
*
|
|
* Copyright (C) 2005-2006 Novell, 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;
|
|
|
|
// determine if user has more than 1 process still running
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
|