Different behaviour of an event object in Windows XP and Windows 7 - winapi

In my C++/winapi program I use an event object to detect if an instance of my application is already running, in order to not let the second instance start.
But in the same time I want to allow multiple instances of the program to run if they are launched using a different user account. E.g. using "runas" command.
(That is: for each user account only 1 instance can run simultaneously)
I use the code that looks like this:
HANDLE hSingleInstance=OpenEvent(EVENT_MODIFY_STATE,FALSE,
"Local\\SingleInstanceEventName");
if(hSingleInstance!=NULL) {
// there is an instance already running
SetEvent(hSingleInstance);// let know the 1st instance that we are trying to start
CloseHandle(hSingleInstance);
return 0; // exit the program
}
else {
// this is the 1st instance
hSingleInstance=CreateEvent(NULL,FALSE,FALSE, "Local\\SingleInstanceEventName");
}
It works as expected in XP - I can run only 1 instance using the same user account, and I can run multiple instances using multiple user accounts.
But in Windows 7, the OpenEvent() function always "finds" my event object, even if the event object is created using another user account. Because of this I cannot run multiple instances using different user accounts (as desired).
What should I change in my code to allow multiple instances be run using diffent user accounts in Windows 7?
Or maybe my approach is completely wrong, then what one is correct?
thank you

All you have to do is include the username in the name of the event somehow. I'm quite frankly a bit surprised that your scenario worked in XP.

I think you're running into security issues here. Generally speaking, one app cannot modify objects created by another app that's running as another user, so if one app creates the event object, an app running as another user should not be able to open it - even it already exits.
There are some subtle changes to this on Vista onwards; the concept of running something 'elevated' introduces an extra wrinkle; it's similar, but not exactly the same, as running as another user. Some resources are allowed through for compat reasons - I can't remember offhand if events/mutexes are in this category.
Either way, as currently written, your code likely is incorrect: part of the problem is that OpenEvent can fail for multiple reasons: your code assumes it's failing because the event is not created, but it could be failing because the event is created but that the calling code does not have permission to modify the object.
As mentioned in one of the other replies, if you want to do this on a per-user basis (but still within the same session), you need to give your events per-user names: add the username to the event's base name, and you should be done.

Related

Detect user is about to log in in Windows 7/8

I need to write a little windows service that should detect when a user is attempting to log in and deny access according to certain criteria, like the hour.
So, I researched the way the Windows Family Safety works when a child has hour restriction, and I noticed that the message received by the user(child) is similar or identical to the one received when a restriction is set using
net user User /time:etc, etc.
so I suspect that's what the Family Safety use.
However, I would like to interact with the "net" command programatically, and besides that I would like to know if there's an event to watch for when a user is attempting to login, or the user has just logged in.
Which Windows API should I look for to get this functionality?
The "net user" commands are available programmatically through the Network Management API. As an example, you can use the NetUserSetInfo function along with the USER_INFO_1020 structure to set the times during which a user can log on.

What process API do I need to hook to track services?

I need to track to a log when a service or application in Windows is started, stopped, and whether it exits successfully or with an error code.
I understand that many services do not log their own start and stop times, or if they exit correctly, so it seems the way to go would have to be inserting a hook into the API that will catch when services/applications request a process space and relinquish it.
My question is what function do I need to hook in order to accomplish this, and is it even possible? I need it to work on Windows XP and 7, both 64-bit.
I think your best bet is to use a device driver. See PsSetCreateProcessNotifyRoutine.
Windows Vista has NotifyServiceStatusChange(), but only for single services. On earlier versions, it's not possible other than polling for changes or watching the event log.
If you're looking for a user-space solution, EnumProcesses() will return a current list. But it won't signal you with changes, you'd have to continually poll it and act on the differences.
If you're watching for a specific application or set of applications, consider assigning them to Job Objects, which are all about allowing you to place limits on processes and manage them externally. I think you could even associate Explorer with a job object, then all tasks launched by the user would be associated with your job object automatically. Something to look into, perhaps.

Launch a winform application from a windows service

Please let me know how do I run the app under current logged in user from the service.
To give you background, I have a VB.NET Windows service whose sole functionality is to run a Winform App at a specified time. Apart from that it also sets a system wakeup timer so that the system can be woken up at the specified time, if it goes into standby/sleep, to run the app. This service has to cater to XP/Vista/Win7 desktops on our network. This service won't run on servers and laptops.
The Winform App shows a UI for the user to provide some inputs. If the user does not provide the input within 15 minutes, then it defaults the value and then goes into system tray icon. The user can click on the icon and change the values later (within in a specified time frame and that too only twice).
There is absolutely no interaction between the service and the winform app apart from the service starting the app. It also monitors if the app has been killed by the user/crashed. If it has been killed/crashed, then a new instance is run after 30 mins from previous run.
If there is no user logged on, then also I want the app to be run at the specified time. As I said before, the app has a default timer. So if some user has just logged off from the system, then defaults would be set by the winform app.
Now coming to why I am stuck with this design - I cannot use TaskScheduler because it has been disabled on all machines and security team is not willing to change it. TaskScheduler had the option to wakeup the machine from sleep and other things. So basically I ended up creating a service which is acting like task scheduler.
Currently when I run the app.exe via process.start() within the service, its running under SYSTEM account as the service is also running under LOCAL SYSTEM. So basically I am not getting any UI. Is there anyway to run it under the current logged in user? I am not worried about multiple user login as we wont be running it on servers and switch user is not enabled on our desktops. Even if somebody has done a remote login via mstsc, then also I need the run the app and show the UI to the user.
Please let me know how do I run the app under current logged in user from the service.
Thanks
askids
There were some additional comments that I posted. But I somehow cannot see it :(
Coming back to the original question. I was able to figure it out after several trial and errors. I will put it in detail.
With Vista and above, services run in isolation from other user sessions. They run in session 0. User sessions run in 1 and above. So basically you need to emulate the process as current logged in user.
Use WTSEnumerateSessions and
get of sessions. Check if the sesion
state is active. This will be
current logged on user session. If
there are no active sessions, it
means there is no logged on user. In
my case, there will be only 1 logged
on user. So I need not figure out
the active session (like others may
need to do).
Use WTSQueryUserToken to get the user token in the active session.
Create a primary user token using DuplicateTokenEx
Create an environment using CreateEnvironmentBlock
Use the information above in the CreateProcessAsUser
The reason why it was working in XP and not in Vista was because it looks like the startup default information is different. After I set wShowWindow flag of the startupinfo structure, the GUI would start appearing.
Dim StartupInfo As New STARTUPINFO()
StartupInfo.cb = Marshal.SizeOf(StartupInfo)
StartupInfo.dwFlags = STARTF_USESHOWWINDOW
StartupInfo.wShowWindow = WINDOW_STATUS.SW_SHOWNORMAL
One more additional info. I was trying to set the default desktop using
StartupInfo.lpDesktop = "WinSta0\\Default"
because of which the application would crash upon launch. So I commented it out.
I still have one final issue. The launched app is not in focus. The GUI appears, but in background. But I am thinking, it will once again have to do with some parameters like above. Once I figure it out, I will add in the details.

What will report an account's permissions?

My service program executes another instance of itself with, essentially, CreateProcess(GetCommandLine()). The child process then uses OpenProcess to get a handle to its parent process (so it can detect when the parent has stopped running). For some customers, OpenProcess fails with ERROR_ACCESS_DENIED. I'm trying to determine the reason and reproduce the circumstances for in-house testing.
I want something I can send to customers (either a program, or instructions for using programs that are already commonly installed on Windows servers) for them to run and generate a report that includes what account the service runs as and what privileges that account and its groups have been granted or denied. How can I collect that information from customers?
Getting the account name is easy -- GetUserName. Getting the rights assigned to that account is a bit more work. If memory serves, the sequence runs something like:
GetKernelObjectSecurity(Current_oject, &security_descriptor)
GetSecurityDescriptorDacl(security_descriptor, &dacl)
GetEffectiveRightsFromAcl(dacl, user_name, &rights)
You might prefer to use GetExplicitEntriesFromAcl for that last step. There is one problem with all this: if they've restricted the user too much, some (or all) of it might fail as well.

Best secure single running app guard on windows

I would like to improve the way how an application is checking that another instance is not already running. Right now we are using named mutexes with checking of running processes.
The goal is to prevent security attacks (as this is security software). My idea right now is that "bulletproof" solution is only to write an driver, that will serve this kind of information and will authenticate client via signed binaries.
Does anyone solved such problem?
What are your opinions and recommendations?
First, let me say that there is ultimately no way to protect your process from agents that have administrator or system access. Even if you write a rootkit driver that intercepts all system calls (a difficult and unsafe practice in of itself), there are still ways to use admin access to get in. You have the wrong design if this is a requirement.
If you set up your secure process to run as a service, you can use the Service Control Manager to start it. The SCM will only start one instance, will monitor that it stays up, allow you to define actions to execute if it crashes, and allow you to query the current status. Since this is controlled by the SCM and the service database can only be modified by administrators, an attacking process would not be able to spoof it.
I don't think there's a secure way of doing this. No matter what kind of system-unique, or user-unique named object you use - malicious 3rd party software can still use the exact same name and that would prevent your application from starting at all.
If you use the method of checking the currently executing processes, and checking if no executable with the same name is running - you'd run into problems, if the malicious software has the same executable name. If you also check the path, of that executable - then it would be possible to run two copies of your app from different locations.
If you create/delete a file when starting/finishing - that might be tricked as well.
The only thing that comes to my mind is you may be able to achieve the desired effect by putting all the logic of your app into a COM object, and then have a GUI application interact with it through COM interfaces. This would, only ensure, that there is only one COM object - you would be able to run as many GUI clients as you want. Note, that I'm not suggesting this as a bulletproof method - it may have it's own holes (for example - someone could make your GUI client to connect to a 3rd party COM object, by simply editing the registry).
So, the short answer - there is no truly secure way of doing this.
I use a named pipe¹, where the name is derived from the conditions that must be unique:
Name of the application (this is not the file name of the executable)
Username of the user who launched the application
If the named pipe creation fails because a pipe with that name already exists, then I know an instance is already running. I use a second lock around this check for thread (process) safety. The named pipe is automatically closed when the application terminates (even if the termination was due to an End Process command).
¹ This may not be the best general option, but in my case I end up sending data on it at a later point in the application lifetime.
In pseudo code:
numberofapps = 0
for each process in processes
if path to module file equals path to this module file
increment numberofapps
if number of apps > 1
exit
See msdn.microsoft.com/en-us/library/ms682623(VS.85).aspx for details on how to enumerate processes.

Resources