ServiceController.ServiceType

  • Thread starter Thread starter Bill Burris
  • Start date Start date
B

Bill Burris

How do I set the ServiceType to InteractiveProcess, since this property is
read only?

Is there a way to set this with code in my Installer class, or a standalone
process?

I normally set this manually in MMC by going to the Log On tab of the
services properties, and selecting Allow service to interact with desktop.

The end users want me to automate this in my install program, so that they
don't have to do it manually.

Bill
 
Hi Bill,

Thanks for posting in this group.
In .Net this can not be done through program. Setting a windows as
"interact with desktop" is a major security risk - windows services running
in the background, logged on as a user different than the desktop user (and
in the worst case, as LocalSystem), can be attacked from the desktop if
they open UI. When they open UI, a rogue desktop app can send corrupted
window messages to it, overrun buffers, and elevate privileges.
..Net Framework devlopment team has determined that allowing a service to
interact with the desktop is a serious security risk. The property,
'ServiceType' is exposed
ReadOnly in the ServiceController class so that we can list/enumerate
existing services which are marked as 'InteractWithDesktop'. We
deliberately made the
property not settable in the installer because we do not support setting a
service to 'InteractWithDesktop' in the framework.

The workaround is to create a GUI app that communicates with the service
using .NET remoting. This is a secure and supported way of doing what you
want. For more information on remoting you can check out
http://www.ingorammer.com/RemotingFAQ/. Also the book "Wrox Professional
C# (2nd Ed)" / Chapter 22 has examples and source code for of creating an
NT service that communicates with graphical clients using TCP.

Hope this helps,

Best regards,
Jeffrey Tan
Microsoft Online Partner Support
Get Secure! - www.microsoft.com/security
This posting is provided "as is" with no warranties and confers no rights.

--------------------
| From: "Bill Burris" <[email protected]>
| Subject: ServiceController.ServiceType
| Date: Tue, 18 Nov 2003 12:04:42 -0700
| Lines: 15
| X-Priority: 3
| X-MSMail-Priority: Normal
| X-Newsreader: Microsoft Outlook Express 6.00.2800.1158
| X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2800.1165
| Message-ID: <[email protected]>
| Newsgroups: microsoft.public.dotnet.languages.csharp
| NNTP-Posting-Host: kzin.phys.ualberta.ca 129.128.162.60
| Path: cpmsftngxa06.phx.gbl!TK2MSFTNGP08.phx.gbl!TK2MSFTNGP10.phx.gbl
| Xref: cpmsftngxa06.phx.gbl microsoft.public.dotnet.languages.csharp:200252
| X-Tomcat-NG: microsoft.public.dotnet.languages.csharp
|
| How do I set the ServiceType to InteractiveProcess, since this property is
| read only?
|
| Is there a way to set this with code in my Installer class, or a
standalone
| process?
|
| I normally set this manually in MMC by going to the Log On tab of the
| services properties, and selecting Allow service to interact with desktop.
|
| The end users want me to automate this in my install program, so that they
| don't have to do it manually.
|
| Bill
|
|
|
 
"Jeffrey Tan[MSFT]" said:
We
deliberately made the
property not settable in the installer because we do not support setting a
service to 'InteractWithDesktop' in the framework.

The workaround is to create a GUI app that communicates with the service
using .NET remoting. This is a secure and supported way of doing what you
want. For more information on remoting you can check out
http://www.ingorammer.com/RemotingFAQ/. Also the book "Wrox Professional
C# (2nd Ed)" / Chapter 22 has examples and source code for of creating an
NT service that communicates with graphical clients using TCP.

Thanks for the info.

I have my application written as a separate program and use remoting for the
service to communicate with the program. I used Ingo Rammer's Advanced .NET
Remoting book to figure this out. This works great if the program is
already running. The problem is when I need to launch the program remotely.
The service will not launch the program using myProcess.Start(), if the
service is not allowed to interact with the desktop.

Our data acquisition systems
(http://csr.phys.ualberta.ca/csr/research/alta.htm), are scattered all over
the province at high schools. These systems are not on the internet so we
connect to them using a modem. The program has a local GUI as well as a
remote GUI. The remote GUI communicates with the program using remoting.
Sometimes the program needs to be restarted, which is why I created a
service for killing and launching the program remotely.

It looks like the only real solution is to remove the GUI from my
application and create a GUI as a separate application. If someone needs to
interact with the program locally they can launch the GUI which communicates
with the real app using remoting.

Bill
 
Hi Bill,

Because windows service can not have the UI, you can not invoke the GUI
directly.
I think you should use remoting to invoke your GUI application.

Best regards,
Jeffrey Tan
Microsoft Online Partner Support
Get Secure! - www.microsoft.com/security
This posting is provided "as is" with no warranties and confers no rights.
 
"Jeffrey Tan[MSFT]" said:
Hi Bill,

Because windows service can not have the UI, you can not invoke the GUI
directly.

I wasn't trying to put the GUI in the service, The service is starting up my
application which has a GUI.
I think you should use remoting to invoke your GUI application.

You can't use remoting to start the application, it needs to be running
before the remoting server code is active.

As a short term solution I could just edit the registry as shown in the
article at:
http://www.codeproject.com/csharp/CsWindowsServiceDesktop.asp

RegistryKey ckey = Registry.LocalMachine.OpenSubKey(
@"SYSTEM\CurrentControlSet\Services\WindowsService1", true);
if(ckey != null)
{
if(ckey.GetValue("Type") != null)
{
ckey.SetValue("Type", ((int)ckey.GetValue("Type") | 256));
}
}

Second solution:

I could create a simple control program whose purpose is to launch or kill
my GUI app. The service will launch this control program. My remote
application will talk to the control program using remoting. This
additional layer between the service and my application should be less than
a days work.

Maybe this second solution won't solve anything, since the program in the
middle will still be running on the same account as the service.

The problem with remoting and windows services is that this 1% of my
application seems to require a large amount of time digging around to get
all the details worked out. Most of my remoting & service code, I got
working back in Beta 2 days but the details keep coming back to haunt me.

Bill
 
Hi Bill,

I am glad, you got some soluitons.
For your second soluiton, as you said, you can not invoke GUI application
through Process class in your service, how do you invoke your control
program in your service?
Is it a console application, so can be invoke?
What does your control program "should be less than a days work." mean?
I am just curious about your soluiton :-)

Best regards,
Jeffrey Tan
Microsoft Online Partner Support
Get Secure! - www.microsoft.com/security
This posting is provided "as is" with no warranties and confers no rights.
 
The control program would be a console application. I would move most of
the code which currently resides in my service into the control program.
The service would run the control program.

The following code is my existing service. In my proposed solution the
AltaManager class and the remoting setup code in OnStart would move into the
control program. For this to work the control program and maybe the service
would have to use the same user account that is normally used to run my
application.

namespace AltaService
{
public class AltaRemotingService : System.ServiceProcess.ServiceBase
{
private static EventLog evt = new EventLog( "Application" );
public static String SVC_NAME = "Alta Remote Manager";

public AltaRemotingService()
{
this.ServiceName = SVC_NAME;
}

static void Main()
{
evt.Source = SVC_NAME;
evt.WriteEntry( "Alta Remoting Service initializing" );
ServiceBase.Run( new AltaRemotingService());
}

protected override void OnStart(string[] args)
{
try
{
RemotingConfiguration.Configure(
AppDomain.CurrentDomain.SetupInformation.ConfigurationFile );
}
catch( Exception e )
{
evt.WriteEntry( e.Message, EventLogEntryType.Error );
}
evt.WriteEntry( "Alta Remoting Service started" );
}

protected override void OnStop()
{
evt.WriteEntry( "Alta Remoting Service stopped" );
}
}

public class AltaManager : MarshalByRefObject
{
private static EventLog evt = new EventLog( "Application" );
private Settings _settings;

public AltaManager()
{
evt.Source = AltaRemotingService.SVC_NAME;
}

public void Startup()
{
LoadSettings();
Process myProcess = new Process();
myProcess.StartInfo.FileName = _settings.FileName;
try
{
myProcess.Start();
}
catch( Exception e )
{
evt.WriteEntry( e.Message + " " + _settings.FileName,
EventLogEntryType.Error );
}
}

public void Shutdown()
{
LoadSettings();
Process[] p;
p = Process.GetProcessesByName( _settings.AppName );
if( p.Length == 0 )
{
evt.WriteEntry( _settings.AppName + " process not found",
EventLogEntryType.Error );
}
else
{
try
{
for( int j = 0 ; j < p.Length ; j++ )
{
if( p[j].Responding )
{
p[j].CloseMainWindow();
}
else
{
p[j].Kill();
}
}
}
catch( Exception e )
{
evt.WriteEntry( e.Message + " " + _settings.AppName,
EventLogEntryType.Error );
}
}
}

public bool Running
{
get
{
LoadSettings();
Process[] p;
p = Process.GetProcessesByName( _settings.AppName );
if( p.Length == 0 )
{
return( false );
}
else
{
return( true );
}
}
}

private void LoadSettings()
{
try
{
XmlSerializer serializer = new XmlSerializer( typeof(Settings) );
TextReader reader = new StreamReader( "AltaSettings.xml" );
_settings = (Settings)serializer.Deserialize( reader );
reader.Close();
}
catch
{
_settings = new Settings();
SaveSettings();
}
}

private void SaveSettings()
{
XmlSerializer serializer = new XmlSerializer( typeof(Settings) );
TextWriter writer = new StreamWriter( "AltaSettings.xml" );
serializer.Serialize( writer, _settings );
writer.Close();
}
}
}

I haven't tried creating the control program, since I am busy trying to
figure out how to create an install program. I was thinking that I was
going to have to write some code to call installutil and put that in as a
custom action. Yesterday, down in the depths of the Creating Installation
Components documentation, I discovered that all I have to do is add the exe
which contains the service and Installer as a custom action. Its great that
Visual Studio makes this so simple, too bad it wasn't easy to find the
information in the documentation.

Bill

"Jeffrey Tan[MSFT]" said:
Hi Bill,

I am glad, you got some soluitons.
For your second soluiton, as you said, you can not invoke GUI application
through Process class in your service, how do you invoke your control
program in your service?
Is it a console application, so can be invoke?
What does your control program "should be less than a days work." mean?
I am just curious about your soluiton :-)

Best regards,
Jeffrey Tan
Microsoft Online Partner Support
Get Secure! - www.microsoft.com/security
This posting is provided "as is" with no warranties and confers no rights.
 
Thanks for the help. Looks like I should take a look through the
walkthroughs, whenever I get a new version of Visual Studio. I wrote my
service in 2001 using Beta 2 and was just trying to create a setup program
for it now, more then 2 years later using VS 2003.

Bill
 
Bill Burris said:
RegistryKey ckey = Registry.LocalMachine.OpenSubKey(
@"SYSTEM\CurrentControlSet\Services\WindowsService1", true);
if(ckey != null)
{
if(ckey.GetValue("Type") != null)
{
ckey.SetValue("Type", ((int)ckey.GetValue("Type") | 256));
}
}

That piece of code I posted before didn't work. It throws a
System.UnauthorizedAccessException.

Here is a piece of code which worked. Just add it to the Installer class.

protected override void OnAfterInstall( IDictionary savedState )
{
base.OnAfterInstall( savedState );

ConnectionOptions coOptions = new ConnectionOptions();
coOptions.Impersonation = ImpersonationLevel.Impersonate;
ManagementScope mgmtScope = new
System.Management.ManagementScope(@"root\CIMV2", coOptions);
mgmtScope.Connect();
ManagementObject wmiService;
ServiceController sc = new ServiceController(
AltaRemotingService.SVC_NAME );
wmiService = new ManagementObject("Win32_Service.Name='" + sc.ServiceName
+ "'");
ManagementBaseObject InParam = wmiService.GetMethodParameters("Change");
InParam["DesktopInteract"] = true;
ManagementBaseObject OutParam = wmiService.InvokeMethod("Change",
InParam, null);
sc.Start();
}

You don't want to use this code unless you have to and know what you are
doing, since it leaves a security hole in your system.

Take a look at:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dncode/html/secure08192002.asp

Bill
 
Hi Bill,

Thanks for your feedback.
I think it is very useful, and it will help many people in this community.
Again thanks for your information.

Best regards,
Jeffrey Tan
Microsoft Online Partner Support
Get Secure! - www.microsoft.com/security
This posting is provided "as is" with no warranties and confers no rights.
 
Back
Top