EventWaitHandle madness!

D

Dilip

I have a problem thats been driving me crazy all day.

I have an application that quietly runs in the background. This
application can only be shutdown externally as it displays no UI. So
I made this application create a named EventWaitHandle and performed a
WaitOne() on it.

From the external application I do an EventWaitHandle.OpenExisting,
passing the appropriate name and do a Set() on it which ensures that
the former application shuts down just fine.

Now I have an ASP.NET application that wants to know if the invisible
application is currently running or not. So like the external
application I do another EventWaitHandle.OpenExisting. For some
unfathomable reason this call *always* throws a
WaitHandleCannotBeOpenedException! I meant this is driving me batty.
I know that the invisible application is running and the EWH has been
successfully created (because the external application is able to open
the event and shut it down just fine). Why does the ASP.NET app throw
an exception?

First I thought might be a security issue, so I used
EventWaitHandleSecurity and EventWaitHandleAccessRule classes to grant
FULL access to the logged on user and the NETWORK SERVICE (under which
my ASP.NET app runs) accounts while creating the EventWaitHandle.

That still doesn't work.

What am I doing wrong?
 
W

Willy Denoyette [MVP]

Dilip said:
I have a problem thats been driving me crazy all day.

I have an application that quietly runs in the background. This
application can only be shutdown externally as it displays no UI. So
I made this application create a named EventWaitHandle and performed a
WaitOne() on it.

From the external application I do an EventWaitHandle.OpenExisting,
passing the appropriate name and do a Set() on it which ensures that
the former application shuts down just fine.

Now I have an ASP.NET application that wants to know if the invisible
application is currently running or not. So like the external
application I do another EventWaitHandle.OpenExisting. For some
unfathomable reason this call *always* throws a
WaitHandleCannotBeOpenedException! I meant this is driving me batty.
I know that the invisible application is running and the EWH has been
successfully created (because the external application is able to open
the event and shut it down just fine). Why does the ASP.NET app throw
an exception?

First I thought might be a security issue, so I used
EventWaitHandleSecurity and EventWaitHandleAccessRule classes to grant
FULL access to the logged on user and the NETWORK SERVICE (under which
my ASP.NET app runs) accounts while creating the EventWaitHandle.

That still doesn't work.

What am I doing wrong?


You need to prefix the name of the object with "Global\" to make it visible
across login sessions , if you don't do this, your named object is only
visible in the local session of the creator.

Willy.
 
D

Dilip

You need to prefix the name of the object with "Global\" to make it visible
across login sessions , if you don't do this, your named object is only
visible in the local session of the creator.

Willy
Thanks for the response. Could you elaborate on what you mean by
login session? I am not sure I understand. Two console applications
(with one waiting on the event and the other setting it) belong to the
same login session but an ASP.NET application doesn't? Is this
somehow related to under what user accounts each application runs?
 
W

Willy Denoyette [MVP]

Dilip said:
From the link here:
http://books.google.com/books?id=74...ts=taB6JHig88&sig=zIaeZZj5tyBy0rktfZ0uFqM0qq4

It appears all named objects are created in the global namespace by
default and belong to one terminal session.

I am a little confused now..!



Named objects are visible across login sessions by default, so when you
create a named object like this:

using(EventWaitHandle ewh = new EventWaitHandle(false,
EventResetMode.AutoReset, "MyWaitHandle"))
{
...
or using "Global\MyWaitHandle", it will be visible as "MyWaitHandle" in the
local namespace and as "Global\\MyWaitHandle" in the global namespace.
This means that when you call "OpenExisting" from another logon session than
you need to prefix the name with "Global\", else the object won't be visible
to the caller.

EventWaitHandle.OpenExisting("Global\\MyWaitHandle");

Sorry about the confusion.

Willy.
 
D

Dilip

Named objects are visible across login sessions by default, so when you
create a named object like this:

            using(EventWaitHandle ewh = new EventWaitHandle(false,
EventResetMode.AutoReset, "MyWaitHandle"))
            {
                ...
or using "Global\MyWaitHandle", it will be visible as "MyWaitHandle" in the
local namespace and as "Global\\MyWaitHandle" in the global namespace.
This means that when you call "OpenExisting" from another logon session than
you need to prefix the name with "Global\", else the object won't be visible
to the caller.

            EventWaitHandle.OpenExisting("Global\\MyWaitHandle");

Sorry about the confusion.

Gotcha Willy! and indeed prefixing with "Global\" did fix my problems
but now I am running into another one which is a result of having
fixed this one :)

See in my ASP.NET application I run a WMI query using
ManagementObjectSearcher and friends to locate a particular process
(because I need to find out from which executable path its running
from). The query fails -- most likely because I am running under
Vista and somehow the NETWORK SERVICE doesn't seem to have enough
privileges to run it (it runs just fine from another console
application and also from the WMI explorer [read further]). I
downloaded a freeware version of the popular WMI Explorer and found
that if I don't run that application as an administrator it just hangs
and doesn't function correctly. So I concluded I somehow need to
elevate the privileges before running WMI queries. I maybe wrong and
there could be another reason but do you know a way around this?
 
W

Willy Denoyette [MVP]

Named objects are visible across login sessions by default, so when you
create a named object like this:

using(EventWaitHandle ewh = new EventWaitHandle(false,
EventResetMode.AutoReset, "MyWaitHandle"))
{
...
or using "Global\MyWaitHandle", it will be visible as "MyWaitHandle" in
the
local namespace and as "Global\\MyWaitHandle" in the global namespace.
This means that when you call "OpenExisting" from another logon session
than
you need to prefix the name with "Global\", else the object won't be
visible
to the caller.

EventWaitHandle.OpenExisting("Global\\MyWaitHandle");

Sorry about the confusion.

Gotcha Willy! and indeed prefixing with "Global\" did fix my problems
but now I am running into another one which is a result of having
fixed this one :)

See in my ASP.NET application I run a WMI query using
ManagementObjectSearcher and friends to locate a particular process
(because I need to find out from which executable path its running
from). The query fails -- most likely because I am running under
Vista and somehow the NETWORK SERVICE doesn't seem to have enough
privileges to run it (it runs just fine from another console
application and also from the WMI explorer [read further]). I
downloaded a freeware version of the popular WMI Explorer and found
that if I don't run that application as an administrator it just hangs
and doesn't function correctly. So I concluded I somehow need to
elevate the privileges before running WMI queries. I maybe wrong and
there could be another reason but do you know a way around this?



NETWORK SERVICE should have sufficient privileges to execute most queries.
Mind to post the failing query?

Willy.
 
D

Dilip

NETWORK SERVICE should have sufficient privileges to execute most queries.
Mind to post the failing query?

Willy.- Hide quoted text -

Its pretty simple. Here is a short but complete list of what I do:

using System;
using System.Collections.Generic;
using System.Text;
using System.Management;

namespace WMITest
{
class Program
{
static void Main(string[] args)
{
string query = "select * from Win32_Process where
Name='Theapplicationinquestion.exe'";
ManagementObjectSearcher mos = new
ManagementObjectSearcher(@"\\.\root\CIMV2", query);
ManagementObjectCollection moc = mos.Get();
if (moc == null || moc.Count != 1)
{
Console.WriteLine("WMI query '" + query + "' failed
for some reason!");
return;
}

foreach (ManagementObject mo in moc)
{
object o = mo["ExecutablePath"];
if (o == null)
return;
}
}
}
}

This code works fine when run from a console application (that doesn't
have any manifest and doesn't ask for any privileges other than what
the logged on account has). This exact same piece of code when run
from an ASP.NET application returns null on the object o when I try to
extract the "ExecutablePath" property. My web.config does not have
any <identity impersonate /> directives.

What is driving me nuts is if I debug this ASP.NET app from the
confines of VS.NET IDE this code works just fine (but I don't want
this confusing the issue for the moment).
 
W

Willy Denoyette [MVP]

Dilip said:
NETWORK SERVICE should have sufficient privileges to execute most
queries.
Mind to post the failing query?

Willy.- Hide quoted text -

Its pretty simple. Here is a short but complete list of what I do:

using System;
using System.Collections.Generic;
using System.Text;
using System.Management;

namespace WMITest
{
class Program
{
static void Main(string[] args)
{
string query = "select * from Win32_Process where
Name='Theapplicationinquestion.exe'";
ManagementObjectSearcher mos = new
ManagementObjectSearcher(@"\\.\root\CIMV2", query);
ManagementObjectCollection moc = mos.Get();
if (moc == null || moc.Count != 1)
{
Console.WriteLine("WMI query '" + query + "' failed
for some reason!");
return;
}

foreach (ManagementObject mo in moc)
{
object o = mo["ExecutablePath"];
if (o == null)
return;
}
}
}
}

This code works fine when run from a console application (that doesn't
have any manifest and doesn't ask for any privileges other than what
the logged on account has). This exact same piece of code when run
from an ASP.NET application returns null on the object o when I try to
extract the "ExecutablePath" property. My web.config does not have
any <identity impersonate /> directives.

What is driving me nuts is if I debug this ASP.NET app from the
confines of VS.NET IDE this code works just fine (but I don't want
this confusing the issue for the moment).


Retrieving the "ExecutablePath" property requires "SeDebugPrivileges",
NETWORK SERVICE does not have this high level privilege, the function fails
silently and null is returned. Why do you need the path of an executable?
You don't want to run ASP.NET with debug privileges enabled do you?

Willy.

Willy.
 
R

rdilipk

Its pretty simple. Here is a short but complete list of what I do:
using System;
using System.Collections.Generic;
using System.Text;
using System.Management;
namespace WMITest
{
class Program
{
static void Main(string[] args)
{
string query = "select * from Win32_Process where
Name='Theapplicationinquestion.exe'";
ManagementObjectSearcher mos = new
ManagementObjectSearcher(@"\\.\root\CIMV2", query);
ManagementObjectCollection moc = mos.Get();
if (moc == null || moc.Count != 1)
{
Console.WriteLine("WMI query '" + query + "' failed
for some reason!");
return;
}
foreach (ManagementObject mo in moc)
{
object o = mo["ExecutablePath"];
if (o == null)
return;
}
}
}
}
This code works fine when run from a console application (that doesn't
have any manifest and doesn't ask for any privileges other than what
the logged on account has). This exact same piece of code when run
from an ASP.NET application returns null on the object o when I try to
extract the "ExecutablePath" property. My web.config does not have
any <identity impersonate /> directives.
What is driving me nuts is if I debug this ASP.NET app from the
confines of VS.NET IDE this code works just fine (but I don't want
this confusing the issue for the moment).

Retrieving the "ExecutablePath" property requires "SeDebugPrivileges",
NETWORK SERVICE does not have this high level privilege, the function fails
silently and null is returned. Why do you need the path of an executable?
You don't want to run ASP.NET with debug privileges enabled do you?

Its a long story. My ASP.NET application provides a functionality to
re-start another application (say app2). So shutting app2 down will
involve accessing that named mutex and just calling Set() on it.
However re-starting it means I would need to know where app2 was
running from before it got shut down so that I can use that path to
run it again.

There are probably other ways to do this (like using the Process class
for example) but I thought using WMI would be cool :-(

What are the ramifications of giving debug privileges to ASP.NET
applications? Even if I wanted to, how do I go about doing it?
 
D

Dilip

Its pretty simple. Here is a short but complete list of what I do:
using System;
using System.Collections.Generic;
using System.Text;
using System.Management;
namespace WMITest
{
class Program
{
static void Main(string[] args)
{
string query = "select * from Win32_Process where
Name='Theapplicationinquestion.exe'";
ManagementObjectSearcher mos = new
ManagementObjectSearcher(@"\\.\root\CIMV2", query);
ManagementObjectCollection moc = mos.Get();
if (moc == null || moc.Count != 1)
{
Console.WriteLine("WMI query '" + query + "' failed
for some reason!");
return;
}
foreach (ManagementObject mo in moc)
{
object o = mo["ExecutablePath"];
if (o == null)
return;
}
}
}
}
This code works fine when run from a console application (that doesn't
have any manifest and doesn't ask for any privileges other than what
the logged on account has). This exact same piece of code when run
from an ASP.NET application returns null on the object o when I try to
extract the "ExecutablePath" property. My web.config does not have
any <identity impersonate /> directives.
What is driving me nuts is if I debug this ASP.NET app from the
confines of VS.NET IDE this code works just fine (but I don't want
this confusing the issue for the moment).

Retrieving the "ExecutablePath" property requires "SeDebugPrivileges",
NETWORK SERVICE does not have this high level privilege, the function fails
silently and null is returned. Why do you need the path of an executable?
You don't want to run ASP.NET with debug privileges enabled do you?

Willy.

Sorry.. one additional piece of information I missed. Before all this
WMI thing happens I found a bunch of code that goes like this:

WindowsImpersonationContext wic = null;
WindowsIdentity id = WindowsIdentity.GetCurrent();
wic = id.Impersonate();

Please don't ask me why but its there because of legacy reasons. I
can't get into that without clouding the problem at hand.

Doesn't this mean by the time I get to executing the WMI query I am
actually impersonating the logged in user? So only the logged on user
now needs SeDebugPrivileges, right?
 
W

Willy Denoyette [MVP]

NETWORK SERVICE should have sufficient privileges to execute most
queries.
Mind to post the failing query?
Willy.- Hide quoted text -
Its pretty simple. Here is a short but complete list of what I do:
using System;
using System.Collections.Generic;
using System.Text;
using System.Management;
namespace WMITest
{
class Program
{
static void Main(string[] args)
{
string query = "select * from Win32_Process where
Name='Theapplicationinquestion.exe'";
ManagementObjectSearcher mos = new
ManagementObjectSearcher(@"\\.\root\CIMV2", query);
ManagementObjectCollection moc = mos.Get();
if (moc == null || moc.Count != 1)
{
Console.WriteLine("WMI query '" + query + "' failed
for some reason!");
return;
}
foreach (ManagementObject mo in moc)
{
object o = mo["ExecutablePath"];
if (o == null)
return;
}
}
}
}
This code works fine when run from a console application (that doesn't
have any manifest and doesn't ask for any privileges other than what
the logged on account has). This exact same piece of code when run
from an ASP.NET application returns null on the object o when I try to
extract the "ExecutablePath" property. My web.config does not have
any <identity impersonate /> directives.
What is driving me nuts is if I debug this ASP.NET app from the
confines of VS.NET IDE this code works just fine (but I don't want
this confusing the issue for the moment).

Retrieving the "ExecutablePath" property requires "SeDebugPrivileges",
NETWORK SERVICE does not have this high level privilege, the function
fails
silently and null is returned. Why do you need the path of an executable?
You don't want to run ASP.NET with debug privileges enabled do you?

Its a long story. My ASP.NET application provides a functionality to
re-start another application (say app2). So shutting app2 down will
involve accessing that named mutex and just calling Set() on it.
However re-starting it means I would need to know where app2 was
running from before it got shut down so that I can use that path to
run it again.

There are probably other ways to do this (like using the Process class
for example) but I thought using WMI would be cool :-(
You can store the path of the application in the config file, or the
registry whetever.
Another option is to store the path in the environment of the NETWORK
SERVICE account.
What are the ramifications of giving debug privileges to ASP.NET
applications? Even if I wanted to, how do I go about doing it?
"debug privileges" is extremely powerful, running with this privilege is a
big NO NO if you care about security.

Willy.
 
B

Ben Voigt [C++ MVP]

Its a long story. My ASP.NET application provides a functionality to
re-start another application (say app2). So shutting app2 down will
involve accessing that named mutex and just calling Set() on it.
However re-starting it means I would need to know where app2 was
running from before it got shut down so that I can use that path to
run it again.

The app needs to restart itself. Knowing the path doesn't solve any
problems, any process started by the ASP.NET application would be running as
NETWORK SERVICE, which is almost certainly not what you want.

Have the application restart itself.

You should probably also consider using a mailslot instead of a mutex, so
you can send different commands (stop, restart, whatever, etc).
 
W

Willy Denoyette [MVP]

Ben Voigt said:
The app needs to restart itself. Knowing the path doesn't solve any
problems, any process started by the ASP.NET application would be running
as NETWORK SERVICE, which is almost certainly not what you want.

I agree that it's preferable not to control (start/stop etc...) applications
from Windows Services, especially ASP and ASP.NET.
However, all depends on the context, if the application is happy to run in
the context of NETWORK SERVICE, then there is nothing wrong with it. If not,
you can even start the external application as another user using the
Process class.


Willy.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top