Skip to content

Commit 204baba

Browse files
committed
Added a basic ServiceControlManager instance object.
1 parent b09a189 commit 204baba

2 files changed

Lines changed: 165 additions & 0 deletions

File tree

NtApiDotNet/NtApiDotNet.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -553,6 +553,7 @@
553553
<Compile Include="Win32\Rpc\Transport\ExtendedErrorInfo.cs" />
554554
<Compile Include="Win32\Rpc\Transport\RpcFaultException.cs" />
555555
<Compile Include="Win32\RpcServer.cs" />
556+
<Compile Include="Win32\Service\ServiceControlManager.cs" />
556557
<Compile Include="Win32\Win32Service.cs" />
557558
<Compile Include="Win32\SafeHandles\SafeAuditBuffer.cs" />
558559
<Compile Include="Win32\SafeHandles\SafeAuthZClientContextHandle.cs" />
Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
// Copyright 2021 Google Inc. All Rights Reserved.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
using NtApiDotNet.Win32.SafeHandles;
16+
using System;
17+
using System.Collections.Generic;
18+
using System.Linq;
19+
20+
namespace NtApiDotNet.Win32.Service
21+
{
22+
/// <summary>
23+
/// Class to represent a handle to the SCM.
24+
/// </summary>
25+
public sealed class ServiceControlManager : IDisposable
26+
{
27+
#region Private Members
28+
private readonly SafeServiceHandle _scm;
29+
private readonly string _machine_name;
30+
31+
private ServiceControlManager(SafeServiceHandle scm, string machine_name)
32+
{
33+
_scm = scm;
34+
_machine_name = machine_name;
35+
}
36+
#endregion
37+
38+
#region Public Constants
39+
/// <summary>
40+
/// Active services database.
41+
/// </summary>
42+
public const string SERVICES_ACTIVE_DATABASE = "ServicesActive";
43+
44+
/// <summary>
45+
/// Failed services database.
46+
/// </summary>
47+
public const string SERVICES_FAILED_DATABASE = "ServicesFailed";
48+
#endregion
49+
50+
#region Static Methods
51+
/// <summary>
52+
/// Open an instance of the SCM.
53+
/// </summary>
54+
/// <param name="machine_name">The machine name for the SCM.</param>
55+
/// <param name="database_name">The database name. Specify SERVICES_ACTIVE_DATABASE or SERVICES_FAILED_DATABASE.
56+
/// If null then SERVICES_ACTIVE_DATABASE is used.</param>
57+
/// <param name="desired_access">The desired access for the SCM connection.</param>
58+
/// <param name="throw_on_error">True to throw on error.</param>
59+
/// <returns>The SCM instance.</returns>
60+
public static NtResult<ServiceControlManager> Open(string machine_name, string database_name,
61+
ServiceControlManagerAccessRights desired_access, bool throw_on_error)
62+
{
63+
if (machine_name == string.Empty)
64+
machine_name = null;
65+
if (database_name == string.Empty)
66+
database_name = null;
67+
SafeServiceHandle scm = Win32NativeMethods.OpenSCManager(machine_name, database_name, desired_access);
68+
if (!scm.IsInvalid)
69+
return new ServiceControlManager(scm, machine_name).CreateResult();
70+
return Win32Utils.CreateResultFromDosError<ServiceControlManager>(throw_on_error);
71+
}
72+
73+
/// <summary>
74+
/// Open an instance of the SCM.
75+
/// </summary>
76+
/// <param name="machine_name">The machine name for the SCM.</param>
77+
/// <param name="database_name">The database name. Specify SERVICES_ACTIVE_DATABASE or SERVICES_FAILED_DATABASE.
78+
/// If null then SERVICES_ACTIVE_DATABASE is used.</param>
79+
/// <param name="desired_access">The desired access for the SCM connection.</param>
80+
/// <returns>The SCM instance.</returns>
81+
public static ServiceControlManager Open(string machine_name, string database_name,
82+
ServiceControlManagerAccessRights desired_access)
83+
{
84+
return Open(machine_name, database_name, desired_access, true).Result;
85+
}
86+
#endregion
87+
88+
#region Public Methods
89+
/// <summary>
90+
/// Get the Win32 services for the SCM.
91+
/// </summary>
92+
/// <param name="service_state">The state of the services to return.</param>
93+
/// <param name="service_types">The types of services to return.</param>
94+
/// <param name="throw_on_error">True throw on error.</param>
95+
/// <returns>The list of services.</returns>
96+
/// <remarks>SCM must have been opened with EnumerateService access.</remarks>
97+
public NtResult<IEnumerable<Win32Service>> GetServices(ServiceState service_state, ServiceType service_types, bool throw_on_error)
98+
{
99+
SERVICE_STATE state;
100+
switch (service_state)
101+
{
102+
case ServiceState.All:
103+
state = SERVICE_STATE.SERVICE_STATE_ALL;
104+
break;
105+
case ServiceState.Active:
106+
state = SERVICE_STATE.SERVICE_ACTIVE;
107+
break;
108+
case ServiceState.InActive:
109+
state = SERVICE_STATE.SERVICE_INACTIVE;
110+
break;
111+
default:
112+
throw new ArgumentException("Invalid service state", nameof(service_state));
113+
}
114+
115+
List<Win32Service> ret_services = new List<Win32Service>();
116+
const int Length = 32 * 1024;
117+
using (var buffer = new SafeHGlobalBuffer(Length))
118+
{
119+
int resume_handle = 0;
120+
while (true)
121+
{
122+
bool ret = Win32NativeMethods.EnumServicesStatusEx(_scm, SC_ENUM_TYPE.SC_ENUM_PROCESS_INFO,
123+
service_types, state, buffer, buffer.Length, out int bytes_needed, out int services_returned,
124+
ref resume_handle, null);
125+
Win32Error error = Win32Utils.GetLastWin32Error();
126+
if (!ret && error != Win32Error.ERROR_MORE_DATA)
127+
{
128+
return error.CreateResultFromDosError<IEnumerable<Win32Service>>(throw_on_error);
129+
}
130+
131+
ENUM_SERVICE_STATUS_PROCESS[] services = new ENUM_SERVICE_STATUS_PROCESS[services_returned];
132+
buffer.ReadArray(0, services, 0, services_returned);
133+
ret_services.AddRange(services.Select(s => new Win32Service(_machine_name, s)));
134+
if (ret)
135+
{
136+
break;
137+
}
138+
}
139+
}
140+
return ret_services.CreateResult().Cast<IEnumerable<Win32Service>>();
141+
}
142+
143+
/// <summary>
144+
/// Get the Win32 services for the SCM.
145+
/// </summary>
146+
/// <param name="service_state">The state of the services to return.</param>
147+
/// <param name="service_types">The types of services to return.</param>
148+
/// <returns>The list of services.</returns>
149+
/// <remarks>SCM must have been opened with EnumerateService access.</remarks>
150+
public IEnumerable<Win32Service> GetServices(ServiceState service_state, ServiceType service_types)
151+
{
152+
return GetServices(service_state, service_types, true).Result;
153+
}
154+
155+
/// <summary>
156+
/// Dispose the object.
157+
/// </summary>
158+
public void Dispose()
159+
{
160+
_scm.Close();
161+
}
162+
#endregion
163+
}
164+
}

0 commit comments

Comments
 (0)