The purpose is to create a new process in session 0 from a process in non 0 console session.
I know some methods that fulfill the purpose, but I want to know why the method described below does not, despite msdn says it should work.
unsigned FindProcessInSession(unsigned SessionId,const wchar_t*ProcessName)
{
PWTS_PROCESS_INFOW pinfo;DWORD Count,Result=0;
if(WTSEnumerateProcessesW(WTS_CURRENT_SERVER_HANDLE,0,1,&pinfo,&Count)){
for(unsigned i=0;i<Count;++i)if(pinfo[i].SessionId==SessionId&&_wcsicmp(pinfo[i].pProcessName,ProcessName)==0){
Result=pinfo[i].ProcessId;break;
}
WTSFreeMemory(pinfo);
}
return Result;
}
int main()
{
HANDLE hProcess=OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION,0,FindProcessInSession(0,L"smss.exe")),ProcessToken,NewToken;
if(hProcess&&OpenProcessToken(hProcess,TOKEN_DUPLICATE,&ProcessToken)&&DuplicateTokenEx(ProcessToken,MAXIMUM_ALLOWED,0,SecurityImpersonation,TokenImpersonation,&NewToken)){
static STARTUPINFOW si={sizeof(STARTUPINFOW)};PROCESS_INFORMATION pi;DWORD SessionId,l;
printf("GetTokenInformation %d\n",GetTokenInformation(NewToken,TokenSessionId,&SessionId,sizeof SessionId,&l));
printf("SessionId %d\n",SessionId);
printf("CreateProcessWithTokenW %d\n",CreateProcessWithTokenW(NewToken,0,L"c:\\windows\\system32\\cmd.exe",0,0,0,0,&si,&pi));
}
}
During testing on my pc,GetTokenInformation successfully output SessionId=0 and CreateProcessWithTokenW created a new process in SYSTEM username, with all privileges from smss.exe. but the new process still ran in whatever session the calling process was in.
msdn on CreateProcessWithTokenW notes
Terminal Services: The process is run in the session specified in the token. By default, this is the same session that called LogonUser. To change the session, use the SetTokenInformation function.
Apparantly the secondary logon service CreateProcessWithTokenW relies on not does not follow the documentation
CreateProcessWithTokenW get SessionId of caller and set this SessionId in token (as side effect - token was modified after CreateProcessWithTokenW. you can call GetTokenInformation again after CreateProcessWithTokenW and view that now already not 0 here. so - CreateProcessWithTokenW can not be used for run process in another session. need use CreateProcessAsUserW. more research here
Related
This question applies to a Lucee 5.x application. I'm not sure if there are differences between how ACF and Lucee handle session scopes across a cluster.
Background: I'm implementing an autoLogin() function in application.cfc - in onRequestStart() - that looks for a token that's stored in a cookie, and then uses it to authenticate the user. Once a token has been used, it gets replaced with a new value, and the cookie is updated. When a token is not found or doesn't work, the cookie is deleted. A session lock is used to prevent multiple concurrent requests from attempting to login the user, which would have unintended side effects.
All the core functionality for this works (on a single node), but I need to make it cluster-friendly. The cluster is already setup correctly (this.sessionCluster = true; in application.cfc, along with a shared Memcached instance that stores session data), and it works fine.
The main questions I have are: (referencing the code below)
The code below uses an exclusive session lock to prevent concurrent requests from executing the login code at the same time. How would you replace the session lock below with one that locks the session across the whole cluster?
The code below assumes that changes to session variables can be seen immediately. Is this true when a session variable is changed on one node, and then a concurrent request on another node tries to access that same variable? If not, is there a way to refresh the session scope to ensure you're getting the latest?
Below is the autoLogin() function: (works on a single node)
private void function autoLogin () {
// multiple, concurrent requests could be hitting this on different nodes in the cluster
// if we're already logged in, nothing to do
if (session.isLoggedIn) {
return;
}
// get the auth token if it exists
var token = cookie.keyExists("auth") && isValid("uuid", cookie.auth) ? cookie.auth : "";
if (token == "") {
// if a token doesn't exists, nothing to do
return;
}
// assertion: user is not logged in and an auth token exists
// attempt to login using the token, but make sure that only one
// request does this at a time - wrap with an exclusive session lock
// lock the session - how would you do this on a cluster?
lock scope="session" type="exclusive" timeout="10" throwontimeout=false {
// check if logged in again - another thread may have succeeded while this
// thread was waiting for the lock to open
if (!session.loggedIn) {
// we can only call this once if user is not logged in!
application.auth.loginWithToken(authToken=token);
}
}
} // autoLogin()
Hello i'm kinda new to laravel and i have a question concerning authentication. I have the following function in my authentication controller:
public function signout()
{
// set logged in status to zero in database
$l = Login::where('user_id', Session::get('user')->user_id)
->where('logged_in', 1)->first();
$l->logged_in = 0;
if ($l->save())
{
// log user out
Auth::logout();
// Forget user session data
Session::forget('user');
// redirect user to login page
return Redirect::to('/account/signin');
}
}
Now in my session config, i have set sessions to expire after 60mins after which the user will obviously be logged out of the system. However that will occur without my other functions executing like setting user logged in status to zero in database or forgetting the user session array. Is there a way i can trigger those functions to execute after login session expire? Thank you in advance.
Update: I've been looking around again ever since i got a down vote for my question to see if there was already a solution to this, from reading the docs i got excited when i came to the "Events" section because i thought i had found a solution however i found out later on that there was no such thing as a "Session::expire" event in laravel, neither is there a function to check whether another user is logged in or not.
Your whole premise is wrong: sessions should have an expiry timestamp that's set when user logs in, and updated on every request if you want to have something like "session times out after 1h of inactivity".
Then you can basically:
Check if session is still valid when user performs a request, by checking the timestamp
Delete expired sessions using a scheduled task, so you keep things clean and tidy in the background
Anyway, if for some reason you end up needing to trigger some actions to happen when a user signs out Laravel actually has an Event that's triggered on user logout: 'auth.logout'
I tried to execute the bellow perl script and locked the user session...
$n=15;
while($n>0)
{
print "$n,";
$n--;
sleep(1);
}
It worked as usual without any extra code..., There was no output when i locked the session, as i locked the session before the next second.
The output seen when I unlocked the session:
C:\Pradeep>perl test.pl
15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,
C:\Pradeep>
When i run the script bellow which I use to connect to a server using Win32::GuiTest functions like
SetForegroundWindow($_);
SendKeys("Password01");
etc...
it connected without any issues and the server login was successful.
But, when i lock my session in the middle of my execution and unlocked the session, the execution of script was completed, but the server login was not done.
use Win32::GuiTest qw(FindWindowLike GetWindowText SetForegroundWindow SendKeys);
system('"start %windir%\system32\mstsc.exe"');
$Win32::GuiTest::debug = 0;
$max_Sleep_time=3;
$Cur_Sleep_time=0;
do
{
sleep(1);
#windows = FindWindowLike(0, "Remote Desktop Connection");
$number_of_windows_opend = scalar(#windows);
$Cur_Sleep_time++;
}while ($number_of_windows_opend==0&&$Cur_Sleep_time!=$max_Sleep_time);
for (#windows) {
SetForegroundWindow($_);
SendKeys("server_name");
SendKeys("{ENTER}");
sleep(10);
#windows_seq = FindWindowLike(0, "Windows Security");
for (#windows_seq) {
SetForegroundWindow($_);
SendKeys("Password01");
SendKeys("{ENTER}");
}
#windows={};
exit;
}
According to me I used the active windows for doing my functionality. So it is not working.
is there any other way i can successfully do the above functionality if the user session is locked in the middle of the execution process. or do i have to make changes in my code?
Instead of using send keys use WMSetText(); function. It takes the window/control HWND and text as input and sets the text to the specified object.
Note: Using WMSetText(); you can just set the text, you can't send keys like {ENTER},{F1} etc...
You've already been told the answer several times:
http://perlmonks.org/?node_id=1073507
http://perlmonks.org/?node_id=1073302
http://perlmonks.org/?node_id=1073530
This is explained in the documentation of Win32::GuiTest. For obvious security reasons you can't send keys to applications when the screen is locked, you can't send keys to appications which aren't active.
I'm new to the Go language (Golang) and I'm writing a web-based application. I'd like to use session variables, like the kind in PHP (variables that are available from one page to the next and unique for a user session). Is there something like that in Go? If not, how would I go about implementing them myself? Or what alternatives methods are there?
You probably want to take a look at gorilla. It has session support as documented here.
Other than that or possibly one of the other web toolkits for go you would have to roll your own.
Possible solutions might be:
goroutine per user session to store session variables in memory.
store your variables in a session cookie.
use a database to store user session data.
I'll leave the implementation details of each of those to the reader.
Here's an alternative in case you just want session support without a complete web toolkit.
https://github.com/bpowers/seshcookie
Here's another alternative (disclosure: I'm the author):
https://github.com/icza/session
Quoting from its doc:
This package provides an easy-to-use, extensible and secure session implementation and management. Package documentation can be found and godoc.org:
https://godoc.org/github.com/icza/session
This is "just" an HTTP session implementation and management, you can use it as-is, or with any existing Go web toolkits and frameworks.
Overview
There are 3 key players in the package:
Session is the (HTTP) session interface. We can use it to store and retrieve constant and variable attributes from it.
Store is a session store interface which is responsible to store sessions and make them retrievable by their IDs at the server side.
Manager is a session manager interface which is responsible to acquire a Session from an (incoming) HTTP request, and to add a Session to an HTTP response to let the client know about the session. A Manager has a backing Store which is responsible to manage Session values at server side.
Players of this package are represented by interfaces, and various implementations are provided for all these players.
You are not bound by the provided implementations, feel free to provide your own implementations for any of the players.
Usage
Usage can't be simpler than this. To get the current session associated with the http.Request:
sess := session.Get(r)
if sess == nil {
// No session (yet)
} else {
// We have a session, use it
}
To create a new session (e.g. on a successful login) and add it to an http.ResponseWriter (to let the client know about the session):
sess := session.NewSession()
session.Add(sess, w)
Let's see a more advanced session creation: let's provide a constant attribute (for the lifetime of the session) and an initial, variable attribute:
sess := session.NewSessionOptions(&session.SessOptions{
CAttrs: map[string]interface{}{"UserName": userName},
Attrs: map[string]interface{}{"Count": 1},
})
And to access these attributes and change value of "Count":
userName := sess.CAttr("UserName")
count := sess.Attr("Count").(int) // Type assertion, you might wanna check if it succeeds
sess.SetAttr("Count", count+1) // Increment count
(Of course variable attributes can be added later on too with Session.SetAttr(), not just at session creation.)
To remove a session (e.g. on logout):
session.Remove(sess, w)
Check out the session demo application which shows all these in action.
Google App Engine support
The package provides support for Google App Engine (GAE) platform.
The documentation doesn't include it (due to the +build appengine build constraint), but here it is: gae_memcache_store.go
The implementation stores sessions in the Memcache and also saves sessions to the Datastore as a backup in case data would be removed from the Memcache. This behaviour is optional, Datastore can be disabled completely. You can also choose whether saving to Datastore happens synchronously (in the same goroutine) or asynchronously (in another goroutine), resulting in faster response times.
We can use NewMemcacheStore() and NewMemcacheStoreOptions() functions to create a session Store implementation which stores sessions in GAE's Memcache. Important to note that since accessing the Memcache relies on Appengine Context which is bound to an http.Request, the returned Store can only be used for the lifetime of a request! Note that the Store will automatically "flush" sessions accessed from it when the Store is closed, so it is very important to close the Store at the end of your request; this is usually done by closing the session manager to which you passed the store (preferably with the defer statement).
So in each request handling we have to create a new session manager using a new Store, and we can use the session manager to do session-related tasks, something like this:
ctx := appengine.NewContext(r)
sessmgr := session.NewCookieManager(session.NewMemcacheStore(ctx))
defer sessmgr.Close() // This will ensure changes made to the session are auto-saved
// in Memcache (and optionally in the Datastore).
sess := sessmgr.Get(r) // Get current session
if sess != nil {
// Session exists, do something with it.
ctx.Infof("Count: %v", sess.Attr("Count"))
} else {
// No session yet, let's create one and add it:
sess = session.NewSession()
sess.SetAttr("Count", 1)
sessmgr.Add(sess, w)
}
Expired sessions are not automatically removed from the Datastore. To remove expired sessions, the package provides a PurgeExpiredSessFromDSFunc() function which returns an http.HandlerFunc. It is recommended to register the returned handler function to a path which then can be defined as a cron job to be called periodically, e.g. in every 30 minutes or so (your choice). As cron handlers may run up to 10 minutes, the returned handler will stop at 8 minutes
to complete safely even if there are more expired, undeleted sessions. It can be registered like this:
http.HandleFunc("/demo/purge", session.PurgeExpiredSessFromDSFunc(""))
Check out the GAE session demo application which shows how it can be used.
cron.yaml file of the demo shows how a cron job can be defined to purge expired sessions.
Check out the GAE session demo application which shows how to use this in action.
I'm writing a Windows service that needs to know whether there are any users currently logged-on in the machine.
So far I've tried Win32_LogonSession (WMI), and LsaEnumerateLogonSessions/LsaGetLogonSessionData (secur32.dll).
Both work, and seem to return the same data, but they are too slow to update when a user log off:
When the system starts, they return "0 interactive users". (OK)
When I log on, they return "1 interactive user". (OK)
But then when I log off, the number of users is kept at 1. After a new log-on, the number is 2, and so on.
Thus Win32_LogonSession nor LsaEnumerateLogonSessions are good enough. The service needs to know within 5 minutes after the last interactive user leaves.
Not even SysInternals' LogonSessions.exe gives up-to-date answers.
Also, the answer cannot be "monitor logon and logoff events and have a counter variable", because the service can be started at any time.
I ended up with the following approach: count the number of interactive sessions which have at least one process running.
1) Get the logon session id for each interactive session.
LsaEnumerateLogonSessions (secur32.dll)
LsaGetLogonSessionData (secur32.dll)
sessionData.LogonType = SECURITY_LOGON_TYPE.Interactive or sessionData.LogonType = SECURITY_LOGON_TYPE.RemoteInteractive
sessionData.LoginID <- Keep this value in a LUID set.
LsaFreeReturnBuffer (secur32.dll)
2) Get the logon session id for each running process.
[First we need to enable the SeDebugPrivilege to the current application.]
GetCurrentProcess (kernel32.dll)
OpenProcessToken TOKEN_ADJUST_PRIVILEGES (advapi32.dll)
LookupPrivilegeValue SE_DEBUG_NAME (advapi32.dll)
AdjustTokenPrivileges (advapi32.dll)
CloseHandle (kernel32.dll)
[Then retrieve the data we want.]
EnumProcesses (psapi.dll)
OpenProcess PROCESS_QUERY_INFORMATION (kernel32.dll)
OpenProcessToken TOKEN_QUERY (advapi32.dll)
GetTokenInformation TOKEN_INFORMATION_CLASS.TokenStatistics (advapi32.dll)
accessTokenStatistics.AuthenticationId <- Keep this value in a LUID set.
CloseHandle (kernel32.dll)
3) Sets intersection cardinality
interactiveSessionsCount = | { sessionData.LoginID } ∩ { accessTokenStatistics.AuthenticationId } |
Obs: sessionData.LoginID and accessTokenStatistics.AuthenticationId are both of type LUID.
WTSEnumerateSessionsA + WTSQuerySessionInformationA work better with detecting active/interfactive sessions.