Process Hacker
other.c
Go to the documentation of this file.
1 /*
2  * Process Hacker Extended Services -
3  * other information
4  *
5  * Copyright (C) 2010-2015 wj32
6  *
7  * This file is part of Process Hacker.
8  *
9  * Process Hacker is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation, either version 3 of the License, or
12  * (at your option) any later version.
13  *
14  * Process Hacker is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with Process Hacker. If not, see <http://www.gnu.org/licenses/>.
21  */
22 
23 #include <phdk.h>
24 #include <windowsx.h>
25 #include "extsrv.h"
26 #include "resource.h"
27 
28 typedef struct _SERVICE_OTHER_CONTEXT
29 {
30  PPH_SERVICE_ITEM ServiceItem;
31 
32  struct
33  {
34  ULONG Ready : 1;
35  ULONG Dirty : 1;
36  ULONG PreshutdownTimeoutValid : 1;
37  ULONG RequiredPrivilegesValid : 1;
38  ULONG SidTypeValid : 1;
39  ULONG LaunchProtectedValid : 1;
40  };
41  HWND PrivilegesLv;
42  PPH_LIST PrivilegeList;
43 
44  ULONG OriginalLaunchProtected;
46 
47 #define SIP(String, Integer) { (String), (PVOID)(Integer) }
48 
50  _In_ PWSTR ServiceName,
51  _In_opt_ SC_HANDLE ServiceHandle,
52  _In_ ULONG InfoLevel,
53  _In_ PVOID Info
54  );
55 
56 static PH_KEY_VALUE_PAIR EspServiceSidTypePairs[] =
57 {
58  SIP(L"None", SERVICE_SID_TYPE_NONE),
59  SIP(L"Restricted", SERVICE_SID_TYPE_RESTRICTED),
60  SIP(L"Unrestricted", SERVICE_SID_TYPE_UNRESTRICTED)
61 };
62 
63 static PH_KEY_VALUE_PAIR EspServiceLaunchProtectedPairs[] =
64 {
65  SIP(L"None", SERVICE_LAUNCH_PROTECTED_NONE),
66  SIP(L"Full (Windows)", SERVICE_LAUNCH_PROTECTED_WINDOWS),
67  SIP(L"Light (Windows)", SERVICE_LAUNCH_PROTECTED_WINDOWS_LIGHT),
68  SIP(L"Light (Antimalware)", SERVICE_LAUNCH_PROTECTED_ANTIMALWARE_LIGHT)
69 };
70 
71 WCHAR *EspServiceSidTypeStrings[3] = { L"None", L"Restricted", L"Unrestricted" };
72 WCHAR *EspServiceLaunchProtectedStrings[4] = { L"None", L"Full (Windows)", L"Light (Windows)", L"Light (Antimalware)" };
73 
75  _In_ ULONG SidType
76  )
77 {
78  PWSTR string;
79 
81  EspServiceSidTypePairs,
82  sizeof(EspServiceSidTypePairs),
83  SidType,
84  &string
85  ))
86  return string;
87  else
88  return L"Unknown";
89 }
90 
92  _In_ PWSTR SidType
93  )
94 {
95  ULONG integer;
96 
98  EspServiceSidTypePairs,
99  sizeof(EspServiceSidTypePairs),
100  SidType,
101  &integer
102  ))
103  return integer;
104  else
105  return -1;
106 }
107 
109  _In_ ULONG LaunchProtected
110  )
111 {
112  PWSTR string;
113 
115  EspServiceLaunchProtectedPairs,
116  sizeof(EspServiceLaunchProtectedPairs),
117  LaunchProtected,
118  &string
119  ))
120  return string;
121  else
122  return L"Unknown";
123 }
124 
126  _In_ PWSTR LaunchProtected
127  )
128 {
129  ULONG integer;
130 
132  EspServiceLaunchProtectedPairs,
133  sizeof(EspServiceLaunchProtectedPairs),
134  LaunchProtected,
135  &integer
136  ))
137  return integer;
138  else
139  return -1;
140 }
141 
143  _In_ HWND hwndDlg,
144  _In_ PSERVICE_OTHER_CONTEXT Context
145  )
146 {
147  NTSTATUS status = STATUS_SUCCESS;
148  SC_HANDLE serviceHandle;
149  ULONG returnLength;
150  SERVICE_PRESHUTDOWN_INFO preshutdownInfo;
151  LPSERVICE_REQUIRED_PRIVILEGES_INFO requiredPrivilegesInfo;
152  SERVICE_SID_INFO sidInfo;
153  SERVICE_LAUNCH_PROTECTED_INFO launchProtectedInfo;
154 
155  if (!(serviceHandle = PhOpenService(Context->ServiceItem->Name->Buffer, SERVICE_QUERY_CONFIG)))
156  return NTSTATUS_FROM_WIN32(GetLastError());
157 
158  // Preshutdown timeout
159 
160  if (QueryServiceConfig2(serviceHandle,
161  SERVICE_CONFIG_PRESHUTDOWN_INFO,
162  (PBYTE)&preshutdownInfo,
163  sizeof(SERVICE_PRESHUTDOWN_INFO),
164  &returnLength
165  ))
166  {
167  SetDlgItemInt(hwndDlg, IDC_PRESHUTDOWNTIMEOUT, preshutdownInfo.dwPreshutdownTimeout, FALSE);
168  Context->PreshutdownTimeoutValid = TRUE;
169  }
170 
171  // Required privileges
172 
173  if (requiredPrivilegesInfo = PhQueryServiceVariableSize(serviceHandle, SERVICE_CONFIG_REQUIRED_PRIVILEGES_INFO))
174  {
175  PWSTR privilege;
176  ULONG privilegeLength;
177  INT lvItemIndex;
178  PH_STRINGREF privilegeSr;
179  PPH_STRING privilegeString;
180  PPH_STRING displayName;
181 
182  privilege = requiredPrivilegesInfo->pmszRequiredPrivileges;
183 
184  if (privilege)
185  {
186  while (TRUE)
187  {
188  privilegeLength = (ULONG)PhCountStringZ(privilege);
189 
190  if (privilegeLength == 0)
191  break;
192 
193  privilegeString = PhCreateStringEx(privilege, privilegeLength * sizeof(WCHAR));
194  PhAddItemList(Context->PrivilegeList, privilegeString);
195 
196  lvItemIndex = PhAddListViewItem(Context->PrivilegesLv, MAXINT, privilege, privilegeString);
197  privilegeSr.Buffer = privilege;
198  privilegeSr.Length = privilegeLength * sizeof(WCHAR);
199 
200  if (PhLookupPrivilegeDisplayName(&privilegeSr, &displayName))
201  {
202  PhSetListViewSubItem(Context->PrivilegesLv, lvItemIndex, 1, displayName->Buffer);
203  PhDereferenceObject(displayName);
204  }
205 
206  privilege += privilegeLength + 1;
207  }
208  }
209 
210  ExtendedListView_SortItems(Context->PrivilegesLv);
211 
212  PhFree(requiredPrivilegesInfo);
213  Context->RequiredPrivilegesValid = TRUE;
214  }
215 
216  // SID type
217 
218  if (QueryServiceConfig2(serviceHandle,
219  SERVICE_CONFIG_SERVICE_SID_INFO,
220  (PBYTE)&sidInfo,
221  sizeof(SERVICE_SID_INFO),
222  &returnLength
223  ))
224  {
225  PhSelectComboBoxString(GetDlgItem(hwndDlg, IDC_SIDTYPE),
226  EspGetServiceSidTypeString(sidInfo.dwServiceSidType), FALSE);
227  Context->SidTypeValid = TRUE;
228  }
229 
230  // Launch protected
231 
232  if (QueryServiceConfig2(serviceHandle,
233  SERVICE_CONFIG_LAUNCH_PROTECTED,
234  (PBYTE)&launchProtectedInfo,
235  sizeof(SERVICE_LAUNCH_PROTECTED_INFO),
236  &returnLength
237  ))
238  {
239  PhSelectComboBoxString(GetDlgItem(hwndDlg, IDC_PROTECTION),
240  EspGetServiceLaunchProtectedString(launchProtectedInfo.dwLaunchProtected), FALSE);
241  Context->LaunchProtectedValid = TRUE;
242  Context->OriginalLaunchProtected = launchProtectedInfo.dwLaunchProtected;
243  }
244 
245  CloseServiceHandle(serviceHandle);
246 
247  return status;
248 }
249 
250 static PPH_STRING EspGetServiceSidString(
252  )
253 {
254  PSID serviceSid = NULL;
255  UNICODE_STRING serviceNameUs;
256  ULONG serviceSidLength = 0;
257  PPH_STRING sidString = NULL;
258 
260  return NULL;
261 
262  PhStringRefToUnicodeString(ServiceName, &serviceNameUs);
263 
264  if (RtlCreateServiceSid_I(&serviceNameUs, serviceSid, &serviceSidLength) == STATUS_BUFFER_TOO_SMALL)
265  {
266  serviceSid = PhAllocate(serviceSidLength);
267 
268  if (NT_SUCCESS(RtlCreateServiceSid_I(&serviceNameUs, serviceSid, &serviceSidLength)))
269  sidString = PhSidToStringSid(serviceSid);
270 
271  PhFree(serviceSid);
272  }
273 
274  return sidString;
275 }
276 
277 static int __cdecl PrivilegeNameCompareFunction(
278  _In_ const void *elem1,
279  _In_ const void *elem2
280  )
281 {
282  PWSTR string1 = *(PWSTR *)elem1;
283  PWSTR string2 = *(PWSTR *)elem2;
284 
285  return wcscmp(string1, string2);
286 }
287 
288 INT_PTR CALLBACK EspServiceOtherDlgProc(
289  _In_ HWND hwndDlg,
290  _In_ UINT uMsg,
291  _In_ WPARAM wParam,
292  _In_ LPARAM lParam
293  )
294 {
295  PSERVICE_OTHER_CONTEXT context;
296 
297  if (uMsg == WM_INITDIALOG)
298  {
299  context = PhAllocate(sizeof(SERVICE_OTHER_CONTEXT));
300  memset(context, 0, sizeof(SERVICE_OTHER_CONTEXT));
301 
302  SetProp(hwndDlg, L"Context", (HANDLE)context);
303  }
304  else
305  {
306  context = (PSERVICE_OTHER_CONTEXT)GetProp(hwndDlg, L"Context");
307 
308  if (uMsg == WM_DESTROY)
309  RemoveProp(hwndDlg, L"Context");
310  }
311 
312  if (!context)
313  return FALSE;
314 
315  switch (uMsg)
316  {
317  case WM_INITDIALOG:
318  {
319  NTSTATUS status;
320  LPPROPSHEETPAGE propSheetPage = (LPPROPSHEETPAGE)lParam;
321  PPH_SERVICE_ITEM serviceItem = (PPH_SERVICE_ITEM)propSheetPage->lParam;
322  HWND privilegesLv;
323 
324  context->ServiceItem = serviceItem;
325 
326  context->PrivilegesLv = privilegesLv = GetDlgItem(hwndDlg, IDC_PRIVILEGES);
327  PhSetListViewStyle(privilegesLv, FALSE, TRUE);
328  PhSetControlTheme(privilegesLv, L"explorer");
329  PhAddListViewColumn(privilegesLv, 0, 0, 0, LVCFMT_LEFT, 140, L"Name");
330  PhAddListViewColumn(privilegesLv, 1, 1, 1, LVCFMT_LEFT, 220, L"Display Name");
331  PhSetExtendedListView(privilegesLv);
332 
333  context->PrivilegeList = PhCreateList(32);
334 
335  if (context->ServiceItem->Type == SERVICE_KERNEL_DRIVER || context->ServiceItem->Type == SERVICE_FILE_SYSTEM_DRIVER)
336  {
337  // Drivers don't support required privileges.
338  EnableWindow(GetDlgItem(hwndDlg, IDC_ADD), FALSE);
339  }
340 
341  EnableWindow(GetDlgItem(hwndDlg, IDC_REMOVE), FALSE);
342 
343  PhAddComboBoxStrings(GetDlgItem(hwndDlg, IDC_SIDTYPE),
344  EspServiceSidTypeStrings, sizeof(EspServiceSidTypeStrings) / sizeof(PWSTR));
345  PhAddComboBoxStrings(GetDlgItem(hwndDlg, IDC_PROTECTION),
347 
349  EnableWindow(GetDlgItem(hwndDlg, IDC_PROTECTION), FALSE);
350 
351  SetDlgItemText(hwndDlg, IDC_SERVICESID,
352  PhGetStringOrDefault(PhAutoDereferenceObject(EspGetServiceSidString(&serviceItem->Name->sr)), L"N/A"));
353 
354  status = EspLoadOtherInfo(hwndDlg, context);
355 
356  if (!NT_SUCCESS(status))
357  {
358  PhShowWarning(hwndDlg, L"Unable to query service information: %s",
360  }
361 
362  context->Ready = TRUE;
363  }
364  break;
365  case WM_DESTROY:
366  {
367  if (context->PrivilegeList)
368  {
369  PhDereferenceObjects(context->PrivilegeList->Items, context->PrivilegeList->Count);
370  PhDereferenceObject(context->PrivilegeList);
371  }
372 
373  PhFree(context);
374  }
375  break;
376  case WM_COMMAND:
377  {
378  switch (LOWORD(wParam))
379  {
380  case IDC_ADD:
381  {
382  NTSTATUS status;
383  LSA_HANDLE policyHandle;
384  LSA_ENUMERATION_HANDLE enumContext;
386  ULONG count;
387  ULONG i;
388  PPH_LIST choices;
389  PPH_STRING selectedChoice = NULL;
390 
391  choices = PhCreateList(100);
392 
393  if (!NT_SUCCESS(status = PhOpenLsaPolicy(&policyHandle, POLICY_VIEW_LOCAL_INFORMATION, NULL)))
394  {
395  PhShowStatus(hwndDlg, L"Unable to open LSA policy", status, 0);
396  break;
397  }
398 
399  enumContext = 0;
400 
401  while (TRUE)
402  {
403  status = LsaEnumeratePrivileges(
404  policyHandle,
405  &enumContext,
406  &buffer,
407  0x100,
408  &count
409  );
410 
411  if (status == STATUS_NO_MORE_ENTRIES)
412  break;
413  if (!NT_SUCCESS(status))
414  break;
415 
416  for (i = 0; i < count; i++)
417  {
418  PhAddItemList(choices, PhaCreateStringEx(buffer[i].Name.Buffer, buffer[i].Name.Length)->Buffer);
419  }
420 
421  LsaFreeMemory(buffer);
422  }
423 
424  LsaClose(policyHandle);
425 
426  qsort(choices->Items, choices->Count, sizeof(PWSTR), PrivilegeNameCompareFunction);
427 
428  while (PhaChoiceDialog(
429  hwndDlg,
430  L"Add privilege",
431  L"Select a privilege to add:",
432  (PWSTR *)choices->Items,
433  choices->Count,
434  NULL,
436  &selectedChoice,
437  NULL,
438  NULL
439  ))
440  {
441  BOOLEAN found = FALSE;
442  PPH_STRING privilegeString;
443  INT lvItemIndex;
444  PPH_STRING displayName;
445 
446  // Check for duplicates.
447  for (i = 0; i < context->PrivilegeList->Count; i++)
448  {
449  if (PhEqualString(context->PrivilegeList->Items[i], selectedChoice, FALSE))
450  {
451  found = TRUE;
452  break;
453  }
454  }
455 
456  if (found)
457  {
458  if (PhShowMessage(
459  hwndDlg,
460  MB_OKCANCEL | MB_ICONERROR,
461  L"The selected privilege has already been added."
462  ) == IDOK)
463  {
464  continue;
465  }
466  else
467  {
468  break;
469  }
470  }
471 
472  PhSetReference(&privilegeString, selectedChoice);
473  PhAddItemList(context->PrivilegeList, privilegeString);
474 
475  lvItemIndex = PhAddListViewItem(context->PrivilegesLv, MAXINT, privilegeString->Buffer, privilegeString);
476 
477  if (PhLookupPrivilegeDisplayName(&privilegeString->sr, &displayName))
478  {
479  PhSetListViewSubItem(context->PrivilegesLv, lvItemIndex, 1, displayName->Buffer);
480  PhDereferenceObject(displayName);
481  }
482 
483  ExtendedListView_SortItems(context->PrivilegesLv);
484 
485  context->Dirty = TRUE;
486  context->RequiredPrivilegesValid = TRUE;
487 
488  break;
489  }
490 
491  PhDereferenceObject(choices);
492  }
493  break;
494  case IDC_REMOVE:
495  {
496  INT lvItemIndex;
497  PPH_STRING privilegeString;
498  ULONG index;
499 
500  lvItemIndex = ListView_GetNextItem(context->PrivilegesLv, -1, LVNI_SELECTED);
501 
502  if (lvItemIndex != -1 && PhGetListViewItemParam(context->PrivilegesLv, lvItemIndex, (PVOID *)&privilegeString))
503  {
504  index = PhFindItemList(context->PrivilegeList, privilegeString);
505 
506  if (index != -1)
507  {
508  PhDereferenceObject(privilegeString);
509  PhRemoveItemList(context->PrivilegeList, index);
510  PhRemoveListViewItem(context->PrivilegesLv, lvItemIndex);
511 
512  context->Dirty = TRUE;
513  context->RequiredPrivilegesValid = TRUE;
514  }
515  }
516  }
517  break;
518  }
519 
520  switch (HIWORD(wParam))
521  {
522  case EN_CHANGE:
523  case CBN_SELCHANGE:
524  {
525  if (context->Ready)
526  {
527  context->Dirty = TRUE;
528 
529  switch (LOWORD(wParam))
530  {
532  context->PreshutdownTimeoutValid = TRUE;
533  break;
534  case IDC_SIDTYPE:
535  context->SidTypeValid = TRUE;
536  break;
537  case IDC_PROTECTION:
538  context->LaunchProtectedValid = TRUE;
539  break;
540  }
541  }
542  }
543  break;
544  }
545  }
546  break;
547  case WM_NOTIFY:
548  {
549  LPNMHDR header = (LPNMHDR)lParam;
550 
551  switch (header->code)
552  {
553  case PSN_KILLACTIVE:
554  {
555  SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, FALSE);
556  }
557  return TRUE;
558  case PSN_APPLY:
559  {
560  SC_HANDLE serviceHandle = NULL;
561  ULONG win32Result = 0;
562  BOOLEAN connectedToPhSvc = FALSE;
563  PPH_STRING launchProtectedString;
564  ULONG launchProtected;
565 
566  SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_NOERROR);
567 
568  launchProtectedString = PhAutoDereferenceObject(PhGetWindowText(GetDlgItem(hwndDlg, IDC_PROTECTION)));
569  launchProtected = EspGetServiceLaunchProtectedInteger(launchProtectedString->Buffer);
570 
571  if (context->LaunchProtectedValid && launchProtected != 0 && launchProtected != context->OriginalLaunchProtected)
572  {
573  if (PhShowMessage(
574  hwndDlg,
575  MB_ICONWARNING | MB_YESNO | MB_DEFBUTTON2,
576  L"Setting service protection will prevent the service from being controlled, modified, or deleted. Do you want to continue?"
577  ) == IDNO)
578  {
579  SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_INVALID);
580  return TRUE;
581  }
582  }
583 
584  if (context->Dirty)
585  {
586  SERVICE_PRESHUTDOWN_INFO preshutdownInfo;
587  SERVICE_REQUIRED_PRIVILEGES_INFO requiredPrivilegesInfo;
588  SERVICE_SID_INFO sidInfo;
589  SERVICE_LAUNCH_PROTECTED_INFO launchProtectedInfo;
590 
591  if (!(serviceHandle = PhOpenService(context->ServiceItem->Name->Buffer, SERVICE_CHANGE_CONFIG)))
592  {
593  win32Result = GetLastError();
594 
595  if (win32Result == ERROR_ACCESS_DENIED && !PhElevated)
596  {
597  // Elevate using phsvc.
598  if (PhUiConnectToPhSvc(hwndDlg, FALSE))
599  {
600  win32Result = 0;
601  connectedToPhSvc = TRUE;
602  }
603  else
604  {
605  // User cancelled elevation.
606  win32Result = ERROR_CANCELLED;
607  goto Done;
608  }
609  }
610  else
611  {
612  goto Done;
613  }
614  }
615 
616  if (context->PreshutdownTimeoutValid)
617  {
618  preshutdownInfo.dwPreshutdownTimeout = GetDlgItemInt(hwndDlg, IDC_PRESHUTDOWNTIMEOUT, NULL, FALSE);
619 
620  if (!EspChangeServiceConfig2(context->ServiceItem->Name->Buffer, serviceHandle,
621  SERVICE_CONFIG_PRESHUTDOWN_INFO, &preshutdownInfo))
622  {
623  win32Result = GetLastError();
624  }
625  }
626 
627  if (context->RequiredPrivilegesValid)
628  {
630  ULONG i;
631 
632  PhInitializeStringBuilder(&sb, 100);
633 
634  for (i = 0; i < context->PrivilegeList->Count; i++)
635  {
636  PhAppendStringBuilder(&sb, &((PPH_STRING)context->PrivilegeList->Items[i])->sr);
638  }
639 
640  requiredPrivilegesInfo.pmszRequiredPrivileges = sb.String->Buffer;
641 
642  if (win32Result == 0 && !EspChangeServiceConfig2(context->ServiceItem->Name->Buffer, serviceHandle,
643  SERVICE_CONFIG_REQUIRED_PRIVILEGES_INFO, &requiredPrivilegesInfo))
644  {
645  win32Result = GetLastError();
646  }
647 
649  }
650 
651  if (context->SidTypeValid)
652  {
653  PPH_STRING sidTypeString;
654 
655  sidTypeString = PhAutoDereferenceObject(PhGetWindowText(GetDlgItem(hwndDlg, IDC_SIDTYPE)));
656  sidInfo.dwServiceSidType = EspGetServiceSidTypeInteger(sidTypeString->Buffer);
657 
658  if (win32Result == 0 && !EspChangeServiceConfig2(context->ServiceItem->Name->Buffer, serviceHandle,
659  SERVICE_CONFIG_SERVICE_SID_INFO, &sidInfo))
660  {
661  win32Result = GetLastError();
662  }
663  }
664 
665  if (context->LaunchProtectedValid)
666  {
667  launchProtectedInfo.dwLaunchProtected = launchProtected;
668 
669  if (!EspChangeServiceConfig2(context->ServiceItem->Name->Buffer, serviceHandle,
670  SERVICE_CONFIG_LAUNCH_PROTECTED, &launchProtectedInfo))
671  {
672  // For now, ignore errors here.
673  // win32Result = GetLastError();
674  }
675  }
676 
677 Done:
678  if (connectedToPhSvc)
680  if (serviceHandle)
681  CloseServiceHandle(serviceHandle);
682 
683  if (win32Result != 0)
684  {
685  if (win32Result == ERROR_CANCELLED || PhShowMessage(
686  hwndDlg,
687  MB_ICONERROR | MB_RETRYCANCEL,
688  L"Unable to change service information: %s",
689  ((PPH_STRING)PhAutoDereferenceObject(PhGetWin32Message(win32Result)))->Buffer
690  ) == IDRETRY)
691  {
692  SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_INVALID);
693  }
694  }
695  }
696 
697  return TRUE;
698  }
699  break;
700  case LVN_ITEMCHANGED:
701  {
702  if (header->hwndFrom == context->PrivilegesLv)
703  {
704  EnableWindow(GetDlgItem(hwndDlg, IDC_REMOVE), ListView_GetSelectedCount(context->PrivilegesLv) == 1);
705  }
706  }
707  break;
708  }
709  }
710  break;
711  }
712 
713  return FALSE;
714 }
715 
717  _In_ PWSTR ServiceName,
718  _In_opt_ SC_HANDLE ServiceHandle,
719  _In_ ULONG InfoLevel,
720  _In_ PVOID Info
721  )
722 {
723  if (ServiceHandle)
724  {
725  return !!ChangeServiceConfig2(ServiceHandle, InfoLevel, Info);
726  }
727  else
728  {
729  NTSTATUS status;
730 
731  if (NT_SUCCESS(status = PhSvcCallChangeServiceConfig2(ServiceName, InfoLevel, Info)))
732  {
733  return TRUE;
734  }
735  else
736  {
737  SetLastError(PhNtStatusToDosError(status));
738  return FALSE;
739  }
740  }
741 }