scmanager_windows_rs/
service_manager.rs1use widestring::U16CString;
5use windows_sys::Win32::{
6 Security::SC_HANDLE,
7 System::Services::{
8 CloseServiceHandle, CreateServiceW, OpenSCManagerW, OpenServiceW, SC_MANAGER_ALL_ACCESS,
9 SERVICE_ALL_ACCESS,
10 },
11};
12
13use crate::{
14 common::{get_last_error, set_privilege},
15 error::{CreateServiceError, OpenServiceError, ServiceManagerError},
16 service::{ServiceErrorControl, ServiceHandle, ServiceStartType, ServiceType},
17};
18
19#[derive(Default, Clone, Debug)]
21pub struct ServiceConfig {
22 pub service_name: String,
23 pub display_name: String,
24 pub binary_path: String,
25 pub service_type: ServiceType,
26 pub start_type: ServiceStartType,
27 pub error_control: ServiceErrorControl,
28}
29
30pub struct ServiceManager {
32 handle: Option<SC_HANDLE>,
33}
34
35impl Drop for ServiceManager {
36 fn drop(&mut self) {
37 if let Some(handle) = self.handle {
38 unsafe {
39 CloseServiceHandle(handle);
40 }
41 }
42 }
43}
44impl ServiceManager {
85 pub fn new() -> Result<Self, ServiceManagerError> {
91 let handle =
92 unsafe { OpenSCManagerW(std::ptr::null(), std::ptr::null(), SC_MANAGER_ALL_ACCESS) };
93
94 if handle == 0 {
95 return Err(ServiceManagerError::from((
96 get_last_error(),
97 "[ServiceManager::new] handle == 0".to_string(),
98 )));
99 }
100
101 set_privilege("SeLoadDriverPrivilege".to_string()).map_err(|_| {
102 ServiceManagerError::AccessDenied(
103 get_last_error(),
104 "[ServiceManager::set_privilege] failed".to_string(),
105 )
106 })?;
107
108 Ok(Self {
109 handle: Some(handle),
110 })
111 }
112
113 pub fn create_service(
119 &self,
120 options: ServiceConfig,
121 ) -> Result<ServiceHandle, CreateServiceError> {
122 let scm_handle = self.handle.ok_or(CreateServiceError::InvalidHandle(
123 get_last_error(),
124 "[create_service] invalid service manager handle".to_string(),
125 ))?;
126
127 let service_name = U16CString::from_str(options.service_name.clone()).map_err(|_| {
128 CreateServiceError::InvalidName(0, "[create_service] invalid service name".to_string())
129 })?;
130 let display_name = U16CString::from_str(options.display_name.clone()).map_err(|_| {
131 CreateServiceError::InvalidName(0, "[create_service] invalid display name".to_string())
132 })?;
133 let binary_path = U16CString::from_str(options.binary_path.clone()).map_err(|_| {
134 CreateServiceError::InvalidParameter(
135 0,
136 "[create_service] invalid binary path".to_string(),
137 )
138 })?;
139
140 let handle = unsafe {
141 CreateServiceW(
142 scm_handle,
143 service_name.as_ptr(),
144 display_name.as_ptr(),
145 SERVICE_ALL_ACCESS,
146 options.service_type as u32,
147 options.start_type as u32,
148 options.error_control as u32,
149 binary_path.as_ptr(),
150 std::ptr::null(),
151 std::ptr::null_mut(),
152 std::ptr::null(),
153 std::ptr::null(),
154 std::ptr::null(),
155 )
156 };
157
158 if handle == 0 {
159 return Err(CreateServiceError::from((
160 get_last_error(),
161 "[create_service] handle == 0".to_string(),
162 )));
163 }
164
165 Ok(ServiceHandle::new(handle))
166 }
167
168 pub fn get_service(&self, service_name: String) -> Result<ServiceHandle, OpenServiceError> {
174 let scm_handle = self.handle.ok_or(OpenServiceError::InvalidHandle(
175 get_last_error(),
176 "[get_service] invalid service manager handle".to_string(),
177 ))?;
178
179 let service_name = U16CString::from_str(service_name)
180 .map_err(|_| OpenServiceError::InvalidName(0, "invalid service named".to_string()))?;
181 let handle = unsafe { OpenServiceW(scm_handle, service_name.as_ptr(), SERVICE_ALL_ACCESS) };
182
183 if handle == 0 {
184 return Err(OpenServiceError::from((
185 get_last_error(),
186 "[get_service] handle == 0".to_string(),
187 )));
188 }
189
190 Ok(ServiceHandle::new(handle))
191 }
192
193 pub fn create_or_get(
199 &self,
200 options: ServiceConfig,
201 ) -> Result<ServiceHandle, CreateServiceError> {
202 if let Ok(service_handle) = self.get_service(options.service_name.clone()) {
203 return Ok(service_handle);
204 }
205
206 self.create_service(options)
207 }
208}