[SC] Don't leak service status info on success
[reactos.git] / base / applications / sc / query.c
1 /*
2 * PROJECT: ReactOS Services
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: base/applications/sc/query.c
5 * PURPOSE: queries service info
6 * COPYRIGHT: Copyright 2005 - 2006 Ged Murphy <gedmurphy@gmail.com>
7 * Copyright 2018 Eric Kohl <eric.kohl@reactos.org>
8 */
9
10 #include "sc.h"
11
12 LPSERVICE_STATUS_PROCESS
13 QueryService(LPCTSTR ServiceName)
14 {
15 SC_HANDLE hSCManager = NULL;
16 LPSERVICE_STATUS_PROCESS pServiceInfo = NULL;
17 SC_HANDLE hSc = NULL;
18 DWORD BufSiz = 0;
19 DWORD BytesNeeded = 0;
20 DWORD Ret;
21
22 hSCManager = OpenSCManager(NULL,
23 NULL,
24 SC_MANAGER_CONNECT);
25 if (hSCManager == NULL)
26 {
27 ReportLastError();
28 return NULL;
29 }
30
31 hSc = OpenService(hSCManager,
32 ServiceName,
33 SERVICE_QUERY_STATUS);
34 if (hSc == NULL)
35 goto fail;
36
37 Ret = QueryServiceStatusEx(hSc,
38 SC_STATUS_PROCESS_INFO,
39 NULL,
40 BufSiz,
41 &BytesNeeded);
42 if ((Ret != 0) || (GetLastError() != ERROR_INSUFFICIENT_BUFFER))
43 goto fail;
44
45 pServiceInfo = (LPSERVICE_STATUS_PROCESS)HeapAlloc(GetProcessHeap(),
46 0,
47 BytesNeeded);
48 if (pServiceInfo == NULL)
49 goto fail;
50
51 if (!QueryServiceStatusEx(hSc,
52 SC_STATUS_PROCESS_INFO,
53 (LPBYTE)pServiceInfo,
54 BytesNeeded,
55 &BytesNeeded))
56 {
57 goto fail;
58 }
59
60 CloseServiceHandle(hSc);
61 CloseServiceHandle(hSCManager);
62 return pServiceInfo;
63
64 fail:
65 ReportLastError();
66 if (pServiceInfo) HeapFree(GetProcessHeap(), 0, pServiceInfo);
67 if (hSc) CloseServiceHandle(hSc);
68 if (hSCManager) CloseServiceHandle(hSCManager);
69 return NULL;
70 }
71
72
73 static
74 DWORD
75 EnumServices(ENUM_SERVICE_STATUS_PROCESS **pServiceStatus,
76 DWORD dwServiceType,
77 DWORD dwServiceState,
78 DWORD dwBufferSize,
79 DWORD dwResumeIndex,
80 LPCTSTR pszGroupName)
81 {
82 SC_HANDLE hSCManager;
83 DWORD BytesNeeded = 0;
84 DWORD ResumeHandle = dwResumeIndex;
85 DWORD NumServices = 0;
86 BOOL Ret;
87
88 hSCManager = OpenSCManager(NULL,
89 NULL,
90 SC_MANAGER_ENUMERATE_SERVICE);
91 if (hSCManager == NULL)
92 {
93 ReportLastError();
94 return 0;
95 }
96
97 if (dwBufferSize == 0)
98 {
99 Ret = EnumServicesStatusEx(hSCManager,
100 SC_ENUM_PROCESS_INFO,
101 dwServiceType,
102 dwServiceState,
103 (LPBYTE)*pServiceStatus,
104 dwBufferSize,
105 &BytesNeeded,
106 &NumServices,
107 &ResumeHandle,
108 pszGroupName);
109 if ((Ret == 0) && (GetLastError() != ERROR_MORE_DATA))
110 {
111 ReportLastError();
112 return 0;
113 }
114
115 dwBufferSize = BytesNeeded;
116 }
117
118 *pServiceStatus = (ENUM_SERVICE_STATUS_PROCESS *)
119 HeapAlloc(GetProcessHeap(),
120 0,
121 dwBufferSize);
122 if (*pServiceStatus != NULL)
123 {
124 if (EnumServicesStatusEx(hSCManager,
125 SC_ENUM_PROCESS_INFO,
126 dwServiceType,
127 dwServiceState,
128 (LPBYTE)*pServiceStatus,
129 dwBufferSize,
130 &BytesNeeded,
131 &NumServices,
132 &ResumeHandle,
133 pszGroupName))
134 {
135 CloseServiceHandle(hSCManager);
136 return NumServices;
137 }
138 }
139
140 ReportLastError();
141 if (*pServiceStatus)
142 HeapFree(GetProcessHeap(), 0, *pServiceStatus);
143
144 CloseServiceHandle(hSCManager);
145
146 return NumServices;
147 }
148
149
150 static
151 BOOL
152 ParseQueryArguments(
153 IN LPCTSTR *ServiceArgs,
154 IN INT ArgCount,
155 OUT PDWORD pdwServiceType,
156 OUT PDWORD pdwServiceState,
157 OUT PDWORD pdwBufferSize,
158 OUT PDWORD pdwResumeIndex,
159 OUT LPCTSTR *ppszGroupName,
160 OUT LPCTSTR *ppszServiceName)
161 {
162 INT TmpCount, TmpIndex;
163 DWORD dwValue;
164
165 TmpCount = ArgCount;
166 TmpIndex = 0;
167 while (TmpCount > 0)
168 {
169 if (!lstrcmpi(ServiceArgs[TmpIndex], _T("type=")))
170 {
171 TmpIndex++;
172 TmpCount--;
173
174 if (TmpCount > 0)
175 {
176 if (!lstrcmpi(ServiceArgs[TmpIndex], _T("service")))
177 {
178 *pdwServiceType = SERVICE_WIN32;
179 }
180 else if (!lstrcmpi(ServiceArgs[TmpIndex], _T("driver")))
181 {
182 *pdwServiceType = SERVICE_DRIVER;
183 }
184 else if (!lstrcmpi(ServiceArgs[TmpIndex], _T("all")))
185 {
186 *pdwServiceType = SERVICE_TYPE_ALL;
187 }
188 else if (!lstrcmpi(ServiceArgs[TmpIndex], _T("interact")))
189 {
190 *pdwServiceType |= SERVICE_INTERACTIVE_PROCESS;
191 }
192 else
193 {
194 _tprintf(_T("ERROR following \"type=\"!\nMust be one of: all, driver, interact, service.\n"));
195 return FALSE;
196 }
197
198 TmpIndex++;
199 TmpCount--;
200 }
201 }
202 else if (!lstrcmpi(ServiceArgs[TmpIndex], _T("state=")))
203 {
204 TmpIndex++;
205 TmpCount--;
206
207 if (TmpCount > 0)
208 {
209 if (!lstrcmpi(ServiceArgs[TmpIndex], _T("active")))
210 {
211 *pdwServiceState = SERVICE_ACTIVE;
212 }
213 else if (!lstrcmpi(ServiceArgs[TmpIndex], _T("inactive")))
214 {
215 *pdwServiceState = SERVICE_INACTIVE;
216 }
217 else if (!lstrcmpi(ServiceArgs[TmpIndex], _T("all")))
218 {
219 *pdwServiceState = SERVICE_STATE_ALL;
220 }
221 else
222 {
223 _tprintf(_T("ERROR following \"state=\"!\nMust be one of: active, all, inactive.\n"));
224 return FALSE;
225 }
226
227 TmpIndex++;
228 TmpCount--;
229 }
230 }
231 else if (!lstrcmpi(ServiceArgs[TmpIndex], _T("bufsize=")))
232 {
233 TmpIndex++;
234 TmpCount--;
235
236 if (TmpCount > 0)
237 {
238 dwValue = _tcstoul(ServiceArgs[TmpIndex], NULL, 10);
239 if (dwValue > 0)
240 {
241 *pdwBufferSize = dwValue;
242 }
243
244 TmpIndex++;
245 TmpCount--;
246 }
247 }
248 else if (!lstrcmpi(ServiceArgs[TmpIndex], _T("ri=")))
249 {
250 TmpIndex++;
251 TmpCount--;
252
253 if (TmpCount >= 0)
254 {
255 dwValue = _tcstoul(ServiceArgs[TmpIndex], NULL, 10);
256 if (dwValue > 0)
257 {
258 *pdwResumeIndex = dwValue;
259 }
260
261 TmpIndex++;
262 TmpCount--;
263 }
264 }
265 else if (!lstrcmpi(ServiceArgs[TmpIndex], _T("group=")))
266 {
267 TmpIndex++;
268 TmpCount--;
269
270 if (TmpCount > 0)
271 {
272 *ppszGroupName = ServiceArgs[TmpIndex];
273
274 TmpIndex++;
275 TmpCount--;
276 }
277 }
278 else
279 {
280 *ppszServiceName = ServiceArgs[TmpIndex];
281
282 TmpIndex++;
283 TmpCount--;
284 }
285 }
286
287 return TRUE;
288 }
289
290
291 BOOL
292 Query(LPCTSTR *ServiceArgs,
293 DWORD ArgCount,
294 BOOL bExtended)
295 {
296 LPENUM_SERVICE_STATUS_PROCESS pServiceStatus = NULL;
297 DWORD NumServices = 0;
298 DWORD dwServiceType = SERVICE_WIN32;
299 DWORD dwServiceState = SERVICE_ACTIVE;
300 DWORD dwBufferSize = 0;
301 DWORD dwResumeIndex = 0;
302 LPCTSTR pszGroupName = NULL;
303 LPCTSTR pszServiceName = NULL;
304 DWORD i;
305
306 #ifdef SCDBG
307 LPCTSTR *TmpArgs = ServiceArgs;
308 INT TmpCnt = ArgCount;
309
310 _tprintf(_T("Arguments:\n"));
311 while (TmpCnt)
312 {
313 _tprintf(_T(" %s\n"), *TmpArgs);
314 TmpArgs++;
315 TmpCnt--;
316 }
317 _tprintf(_T("\n"));
318 #endif /* SCDBG */
319
320 /* Parse arguments */
321 if (!ParseQueryArguments(ServiceArgs,
322 ArgCount,
323 &dwServiceType,
324 &dwServiceState,
325 &dwBufferSize,
326 &dwResumeIndex,
327 &pszGroupName,
328 &pszServiceName))
329 return FALSE;
330
331 #ifdef SCDBG
332 _tprintf(_T("Service type: %lx\n"), dwServiceType);
333 _tprintf(_T("Service state: %lx\n"), dwServiceState);
334 _tprintf(_T("Buffer size: %lu\n"), dwBufferSize);
335 _tprintf(_T("Resume index: %lu\n"), dwResumeIndex);
336 _tprintf(_T("Group name: %s\n"), pszGroupName);
337 _tprintf(_T("Service name: %s\n"), pszServiceName);
338 #endif
339
340 if (pszServiceName)
341 {
342 /* Print only the requested service */
343
344 LPSERVICE_STATUS_PROCESS pStatus;
345
346 pStatus = QueryService(pszServiceName);
347 if (pStatus)
348 {
349 PrintService(pszServiceName,
350 NULL,
351 pStatus,
352 bExtended);
353
354 HeapFree(GetProcessHeap(), 0, pStatus);
355 }
356 }
357 else
358 {
359 /* Print all matching services */
360
361 NumServices = EnumServices(&pServiceStatus,
362 dwServiceType,
363 dwServiceState,
364 dwBufferSize,
365 dwResumeIndex,
366 pszGroupName);
367 if (NumServices == 0)
368 return FALSE;
369
370 for (i = 0; i < NumServices; i++)
371 {
372 PrintService(pServiceStatus[i].lpServiceName,
373 pServiceStatus[i].lpDisplayName,
374 &pServiceStatus[i].ServiceStatusProcess,
375 bExtended);
376 }
377
378 #ifdef SCDBG
379 _tprintf(_T("number : %lu\n"), NumServices);
380 #endif
381
382 if (pServiceStatus)
383 HeapFree(GetProcessHeap(), 0, pServiceStatus);
384 }
385
386 return TRUE;
387 }