Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1082 lines
30 KiB

  1. /*++
  2. Copyright (c) 1995-2001 Microsoft Corporation
  3. Module Name:
  4. util.c
  5. Abstract:
  6. This module contains general utility routines used by cfgmgr32 code.
  7. INVALID_DEVINST
  8. CopyFixedUpDeviceId
  9. PnPUnicodeToMultiByte
  10. PnPMultiByteToUnicode
  11. PnPRetrieveMachineName
  12. PnPGetVersion
  13. PnPGetGlobalHandles
  14. EnablePnPPrivileges
  15. IsRemoteServiceRunning
  16. Author:
  17. Paula Tomlinson (paulat) 6-22-1995
  18. Environment:
  19. User mode only.
  20. Revision History:
  21. 22-Jun-1995 paulat
  22. Creation and initial implementation.
  23. --*/
  24. //
  25. // includes
  26. //
  27. #include "precomp.h"
  28. #include "cfgi.h"
  29. #include "setupapi.h"
  30. #include "spapip.h"
  31. //
  32. // Private prototypes
  33. //
  34. BOOL
  35. EnablePnPPrivileges(
  36. VOID
  37. );
  38. //
  39. // global data
  40. //
  41. extern PVOID hLocalStringTable; // MODIFIED by PnPGetGlobalHandles
  42. extern PVOID hLocalBindingHandle; // MODIFIED by PnPGetGlobalHandles
  43. extern WORD LocalServerVersion; // MODIFIED by PnPGetVersion
  44. extern WCHAR LocalMachineNameNetBIOS[]; // NOT MODIFIED BY THIS FILE
  45. extern CRITICAL_SECTION BindingCriticalSection; // NOT MODIFIED IN THIS FILE
  46. extern CRITICAL_SECTION StringTableCriticalSection; // NOT MODIFIED IN THIS FILE
  47. LUID gLuidLoadDriverPrivilege;
  48. LUID gLuidUndockPrivilege;
  49. BOOL
  50. INVALID_DEVINST(
  51. PWSTR pDeviceID
  52. )
  53. /*++
  54. Routine Description:
  55. This routine attempts a simple check whether the pDeviceID string
  56. returned from StringTableStringFromID is valid or not. It does
  57. this simply by dereferencing the pointer and comparing the first
  58. character in the string against the range of characters for a valid
  59. device id. If the string is valid but it's not an existing device id
  60. then this error will be caught later.
  61. Arguments:
  62. pDeviceID Supplies a pointer to the string to be validated.
  63. Return Value:
  64. If it's invalid it returns TRUE, otherwise it returns FALSE.
  65. --*/
  66. {
  67. BOOL Status = FALSE;
  68. try {
  69. if ((!ARGUMENT_PRESENT(pDeviceID)) ||
  70. (*pDeviceID <= TEXT(' ')) ||
  71. (*pDeviceID > (TCHAR)0x7F) ||
  72. (*pDeviceID == TEXT(','))) {
  73. Status = TRUE;
  74. }
  75. } except(EXCEPTION_EXECUTE_HANDLER) {
  76. Status = TRUE;
  77. }
  78. return Status;
  79. } // INVALID_DEVINST
  80. VOID
  81. CopyFixedUpDeviceId(
  82. OUT LPTSTR DestinationString,
  83. IN LPCTSTR SourceString,
  84. IN DWORD SourceStringLen
  85. )
  86. /*++
  87. Routine Description:
  88. This routine copies a device id, fixing it up as it does the copy.
  89. 'Fixing up' means that the string is made upper-case, and that the
  90. following character ranges are turned into underscores (_):
  91. c <= 0x20 (' ')
  92. c > 0x7F
  93. c == 0x2C (',')
  94. (NOTE: This algorithm is also implemented in the Config Manager APIs,
  95. and must be kept in sync with that routine. To maintain device identifier
  96. compatibility, these routines must work the same as Win95.)
  97. Arguments:
  98. DestinationString - Supplies a pointer to the destination string buffer
  99. where the fixed-up device id is to be copied. This buffer must
  100. be large enough to hold a copy of the source string (including
  101. terminating NULL).
  102. SourceString - Supplies a pointer to the (null-terminated) source
  103. string to be fixed up.
  104. SourceStringLen - Supplies the length, in characters, of the source
  105. string (not including terminating NULL).
  106. Return Value:
  107. None.
  108. --*/
  109. {
  110. PTCHAR p;
  111. try {
  112. CopyMemory(DestinationString,
  113. SourceString,
  114. ((SourceStringLen + 1) * sizeof(TCHAR)));
  115. CharUpperBuff(DestinationString, SourceStringLen);
  116. for(p = DestinationString; *p; p++) {
  117. if((*p <= TEXT(' ')) ||
  118. (*p > (TCHAR)0x7F) ||
  119. (*p == TEXT(','))) {
  120. *p = TEXT('_');
  121. }
  122. }
  123. } except(EXCEPTION_EXECUTE_HANDLER) {
  124. NOTHING;
  125. }
  126. } // CopyFixedUpDeviceId
  127. CONFIGRET
  128. PnPUnicodeToMultiByte(
  129. IN PWSTR UnicodeString,
  130. IN ULONG UnicodeStringLen,
  131. OUT PSTR AnsiString OPTIONAL,
  132. IN OUT PULONG AnsiStringLen
  133. )
  134. /*++
  135. Routine Description:
  136. Convert a string from unicode to ansi.
  137. Arguments:
  138. UnicodeString - Supplies string to be converted.
  139. UnicodeStringLen - Specifies the size, in bytes, of the string to be
  140. converted.
  141. AnsiString - Optionally, supplies a buffer to receive the ANSI
  142. string.
  143. AnsiStringLen - Supplies the address of a variable that contains the
  144. size, in bytes, of the buffer pointed to by AnsiString.
  145. This API replaces the initial size with the number of
  146. bytes of data copied to the buffer. If the variable is
  147. initially zero, the API replaces it with the buffer size
  148. needed to receive all the registry data. In this case,
  149. the AnsiString parameter is ignored.
  150. Return Value:
  151. Returns a CONFIGRET code.
  152. --*/
  153. {
  154. CONFIGRET Status = CR_SUCCESS;
  155. NTSTATUS ntStatus;
  156. ULONG ulAnsiStringLen = 0;
  157. try {
  158. //
  159. // Validate parameters
  160. //
  161. if ((!ARGUMENT_PRESENT(AnsiStringLen)) ||
  162. (!ARGUMENT_PRESENT(AnsiString)) && (*AnsiStringLen != 0)) {
  163. Status = CR_INVALID_POINTER;
  164. goto Clean0;
  165. }
  166. //
  167. // Determine the size required for the ANSI string representation.
  168. //
  169. ntStatus = RtlUnicodeToMultiByteSize(&ulAnsiStringLen,
  170. UnicodeString,
  171. UnicodeStringLen);
  172. if (!NT_SUCCESS(ntStatus)) {
  173. Status = CR_FAILURE;
  174. goto Clean0;
  175. }
  176. if ((!ARGUMENT_PRESENT(AnsiString)) ||
  177. (*AnsiStringLen < ulAnsiStringLen)) {
  178. *AnsiStringLen = ulAnsiStringLen;
  179. Status = CR_BUFFER_SMALL;
  180. goto Clean0;
  181. }
  182. //
  183. // Perform the conversion.
  184. //
  185. ntStatus = RtlUnicodeToMultiByteN(AnsiString,
  186. *AnsiStringLen,
  187. &ulAnsiStringLen,
  188. UnicodeString,
  189. UnicodeStringLen);
  190. ASSERT(NT_SUCCESS(ntStatus));
  191. ASSERT(ulAnsiStringLen <= *AnsiStringLen);
  192. if (!NT_SUCCESS(ntStatus)) {
  193. Status = CR_FAILURE;
  194. }
  195. *AnsiStringLen = ulAnsiStringLen;
  196. Clean0:
  197. NOTHING;
  198. } except(EXCEPTION_EXECUTE_HANDLER) {
  199. Status = CR_FAILURE;
  200. }
  201. return Status;
  202. } // PnPUnicodeToMultiByte
  203. CONFIGRET
  204. PnPMultiByteToUnicode(
  205. IN PSTR AnsiString,
  206. IN ULONG AnsiStringLen,
  207. OUT PWSTR UnicodeString OPTIONAL,
  208. IN OUT PULONG UnicodeStringLen
  209. )
  210. /*++
  211. Routine Description:
  212. Convert a string from ansi to unicode.
  213. Arguments:
  214. AnsiString - Supplies string to be converted.
  215. AnsiStringLen - Specifies the size, in bytes, of the string to be
  216. converted.
  217. UnicodeString - Optionally, supplies a buffer to receive the Unicode
  218. string.
  219. UnicodeStringLen - Supplies the address of a variable that contains the
  220. size, in bytes, of the buffer pointed to by UnicodeString.
  221. This API replaces the initial size with the number of
  222. bytes of data copied to the buffer. If the variable is
  223. initially zero, the API replaces it with the buffer size
  224. needed to receive all the registry data. In this case,
  225. the UnicodeString parameter is ignored.
  226. Return Value:
  227. Returns a CONFIGRET code.
  228. --*/
  229. {
  230. CONFIGRET Status = CR_SUCCESS;
  231. NTSTATUS ntStatus;
  232. ULONG ulUnicodeStringLen = 0;
  233. try {
  234. //
  235. // Validate parameters
  236. //
  237. if ((!ARGUMENT_PRESENT(UnicodeStringLen)) ||
  238. (!ARGUMENT_PRESENT(UnicodeString)) && (*UnicodeStringLen != 0)) {
  239. Status = CR_INVALID_POINTER;
  240. goto Clean0;
  241. }
  242. //
  243. // Determine the size required for the ANSI string representation.
  244. //
  245. ntStatus = RtlMultiByteToUnicodeSize(&ulUnicodeStringLen,
  246. AnsiString,
  247. AnsiStringLen);
  248. if (!NT_SUCCESS(ntStatus)) {
  249. Status = CR_FAILURE;
  250. goto Clean0;
  251. }
  252. if ((!ARGUMENT_PRESENT(UnicodeString)) ||
  253. (*UnicodeStringLen < ulUnicodeStringLen)) {
  254. *UnicodeStringLen = ulUnicodeStringLen;
  255. Status = CR_BUFFER_SMALL;
  256. goto Clean0;
  257. }
  258. //
  259. // Perform the conversion.
  260. //
  261. ntStatus = RtlMultiByteToUnicodeN(UnicodeString,
  262. *UnicodeStringLen,
  263. &ulUnicodeStringLen,
  264. AnsiString,
  265. AnsiStringLen);
  266. ASSERT(NT_SUCCESS(ntStatus));
  267. ASSERT(ulUnicodeStringLen <= *UnicodeStringLen);
  268. if (!NT_SUCCESS(ntStatus)) {
  269. Status = CR_FAILURE;
  270. }
  271. *UnicodeStringLen = ulUnicodeStringLen;
  272. Clean0:
  273. NOTHING;
  274. } except(EXCEPTION_EXECUTE_HANDLER) {
  275. Status = CR_FAILURE;
  276. }
  277. return Status;
  278. } // PnPMultiByteToUnicode
  279. BOOL
  280. PnPRetrieveMachineName(
  281. IN HMACHINE hMachine,
  282. OUT LPWSTR pszMachineName
  283. )
  284. /*++
  285. Routine Description:
  286. Optimized version of PnPConnect, only returns the machine name
  287. associated with this connection.
  288. Arguments:
  289. hMachine Information about this connection
  290. pszMachineName Returns machine name specified when CM_Connect_Machine
  291. was called.
  292. ** This buffer must be at least (MAX_PATH + 3)
  293. characters long. **
  294. Return Value:
  295. Return TRUE if the function succeeds and FALSE if it fails.
  296. --*/
  297. {
  298. BOOL Status = TRUE;
  299. try {
  300. if (hMachine == NULL) {
  301. //
  302. // local machine scenario
  303. //
  304. // use the global local machine name string that was filled
  305. // when the DLL initialized.
  306. //
  307. lstrcpy(pszMachineName, LocalMachineNameNetBIOS);
  308. } else {
  309. //
  310. // remote machine scenario
  311. //
  312. // validate the machine handle.
  313. //
  314. if (((PPNP_MACHINE)hMachine)->ulSignature != (ULONG)MACHINE_HANDLE_SIGNATURE) {
  315. Status = FALSE;
  316. goto Clean0;
  317. }
  318. //
  319. // use information within the hMachine handle to fill in the
  320. // machine name. The hMachine info was set on a previous call
  321. // to CM_Connect_Machine.
  322. //
  323. lstrcpy(pszMachineName, ((PPNP_MACHINE)hMachine)->szMachineName);
  324. }
  325. Clean0:
  326. NOTHING;
  327. } except(EXCEPTION_EXECUTE_HANDLER) {
  328. Status = FALSE;
  329. }
  330. return Status;
  331. } // PnPRetrieveMachineName
  332. BOOL
  333. PnPGetVersion(
  334. IN HMACHINE hMachine,
  335. IN WORD * pwVersion
  336. )
  337. /*++
  338. Routine Description:
  339. This routine returns the internal server version for the specified machine
  340. connection, as returned by the RPC server interface routine
  341. PNP_GetVersionInternal. If the PNP_GetVersionInternal interface does not
  342. exist on the specified machine, this routine returns the version as reported
  343. by PNP_GetVersion.
  344. Arguments:
  345. hMachine - Information about this connection
  346. pwVersion - Receives the internal server version.
  347. Return Value:
  348. Return TRUE if the function succeeds and FALSE if it fails.
  349. Notes:
  350. The version reported by PNP_GetVersion is defined to be constant, at 0x0400.
  351. The version returned by PNP_GetVersionInternal may change with each release
  352. of the product, starting with 0x0501 for Windows NT 5.1.
  353. --*/
  354. {
  355. BOOL Status = TRUE;
  356. handle_t hBinding = NULL;
  357. CONFIGRET crStatus;
  358. WORD wVersionInternal;
  359. try {
  360. if (pwVersion == NULL) {
  361. return FALSE;
  362. }
  363. if (hMachine == NULL) {
  364. //
  365. // local machine scenario
  366. //
  367. if (LocalServerVersion != 0) {
  368. //
  369. // local server version has already been retrieved.
  370. //
  371. *pwVersion = LocalServerVersion;
  372. } else {
  373. //
  374. // retrieve binding handle for the local machine.
  375. //
  376. if (!PnPGetGlobalHandles(hMachine, NULL, &hBinding)) {
  377. return FALSE;
  378. }
  379. ASSERT(hBinding);
  380. //
  381. // initialize the version supplied to the internal client
  382. // version, in case the server wants to adjust the response
  383. // based on the client version.
  384. //
  385. wVersionInternal = (WORD)CFGMGR32_VERSION_INTERNAL;
  386. RpcTryExcept {
  387. //
  388. // call rpc service entry point
  389. //
  390. crStatus = PNP_GetVersionInternal(
  391. hBinding, // rpc binding
  392. &wVersionInternal); // internal server version
  393. }
  394. RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
  395. KdPrintEx((DPFLTR_PNPMGR_ID,
  396. DBGF_WARNINGS,
  397. "PNP_GetVersionInternal caused an exception (%d)\n",
  398. RpcExceptionCode()));
  399. crStatus = MapRpcExceptionToCR(RpcExceptionCode());
  400. }
  401. RpcEndExcept
  402. if (crStatus == CR_SUCCESS) {
  403. //
  404. // PNP_GetVersionInternal exists on NT 5.1 and later.
  405. //
  406. ASSERT(wVersionInternal >= (WORD)0x0501);
  407. //
  408. // initialize the global local server version.
  409. //
  410. LocalServerVersion = *pwVersion = wVersionInternal;
  411. } else {
  412. //
  413. // we successfully retrieved a local binding handle, but
  414. // PNP_GetVersionInternal failed for some reason other than
  415. // the server not being available.
  416. //
  417. ASSERT(0);
  418. //
  419. // although we know this version of the client should match
  420. // a version of the server where PNP_GetVersionInternal is
  421. // available, it's technically possible (though unsupported)
  422. // that this client is communicating with a downlevel server
  423. // on the local machine, so we'll have to resort to calling
  424. // PNP_GetVersion.
  425. //
  426. RpcTryExcept {
  427. //
  428. // call rpc service entry point
  429. //
  430. crStatus = PNP_GetVersion(
  431. hBinding, // rpc binding
  432. &wVersionInternal); // server version
  433. }
  434. RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
  435. KdPrintEx((DPFLTR_PNPMGR_ID,
  436. DBGF_WARNINGS,
  437. "PNP_GetVersion caused an exception (%d)\n",
  438. RpcExceptionCode()));
  439. crStatus = MapRpcExceptionToCR(RpcExceptionCode());
  440. }
  441. RpcEndExcept
  442. if (crStatus == CR_SUCCESS) {
  443. //
  444. // PNP_GetVersion should always return 0x0400 on all servers.
  445. //
  446. ASSERT(wVersionInternal == (WORD)0x0400);
  447. //
  448. // initialize the global local server version.
  449. //
  450. LocalServerVersion = *pwVersion = wVersionInternal;
  451. } else {
  452. //
  453. // nothing more we can do here but fail.
  454. //
  455. ASSERT(0);
  456. Status = FALSE;
  457. }
  458. }
  459. }
  460. } else {
  461. //
  462. // remote machine scenario
  463. //
  464. // validate the machine handle.
  465. //
  466. if (((PPNP_MACHINE)hMachine)->ulSignature != (ULONG)MACHINE_HANDLE_SIGNATURE) {
  467. return FALSE;
  468. }
  469. //
  470. // use information within the hMachine handle to fill in the
  471. // version. The hMachine info was set on a previous call to
  472. // CM_Connect_Machine.
  473. //
  474. *pwVersion = ((PPNP_MACHINE)hMachine)->wVersion;
  475. }
  476. } except(EXCEPTION_EXECUTE_HANDLER) {
  477. Status = FALSE;
  478. }
  479. return Status;
  480. } // PnPGetVersion
  481. BOOL
  482. PnPGetGlobalHandles(
  483. IN HMACHINE hMachine,
  484. OUT PVOID *phStringTable, OPTIONAL
  485. OUT PVOID *phBindingHandle OPTIONAL
  486. )
  487. /*++
  488. Routine Description:
  489. This routine retrieves a handle to the string table and/or the rpc binding
  490. handle for the specified server machine connection.
  491. Arguments:
  492. hMachine - Specifies a server machine connection handle, as returned
  493. by CM_Connect_Machine.
  494. phStringTable - Optionally, specifies an address to receive a handle to
  495. the string table for the specified server machine
  496. connection.
  497. phBindingHandle - Optionally, specifies an address to receive the RPC
  498. binding handle for the specifies server machine
  499. connection.
  500. Return value:
  501. Returns TRUE if successful, FALSE otherwise.
  502. --*/
  503. {
  504. BOOL bStatus = TRUE;
  505. try {
  506. EnablePnPPrivileges();
  507. if (phStringTable != NULL) {
  508. if (hMachine == NULL) {
  509. //------------------------------------------------------
  510. // Retrieve String Table Handle for the local machine
  511. //-------------------------------------------------------
  512. EnterCriticalSection(&StringTableCriticalSection);
  513. if (hLocalStringTable != NULL) {
  514. //
  515. // local string table has already been created
  516. //
  517. *phStringTable = hLocalStringTable;
  518. } else {
  519. //
  520. // first time, initialize the local string table
  521. //
  522. hLocalStringTable = pSetupStringTableInitialize();
  523. if (hLocalStringTable == NULL) {
  524. bStatus = FALSE;
  525. *phStringTable = NULL;
  526. KdPrintEx((DPFLTR_PNPMGR_ID,
  527. DBGF_ERRORS,
  528. "CFGMGR32: failed to initialize local string table\n"));
  529. goto Clean0;
  530. }
  531. //
  532. // No matter how the string table is implemented, I never
  533. // want to have a string id of zero - this would generate
  534. // an invalid devinst. So, add a small priming string just
  535. // to be safe.
  536. //
  537. pSetupStringTableAddString(hLocalStringTable,
  538. PRIMING_STRING,
  539. STRTAB_CASE_SENSITIVE);
  540. *phStringTable = hLocalStringTable;
  541. }
  542. LeaveCriticalSection(&StringTableCriticalSection);
  543. } else {
  544. //-------------------------------------------------------
  545. // Retrieve String Table Handle for the remote machine
  546. //-------------------------------------------------------
  547. //
  548. // validate the machine handle.
  549. //
  550. if (((PPNP_MACHINE)hMachine)->ulSignature != (ULONG)MACHINE_HANDLE_SIGNATURE) {
  551. bStatus = FALSE;
  552. goto Clean0;
  553. }
  554. //
  555. // use information within the hMachine handle to set the string
  556. // table handle. The hMachine info was set on a previous call
  557. // to CM_Connect_Machine.
  558. //
  559. *phStringTable = ((PPNP_MACHINE)hMachine)->hStringTable;
  560. }
  561. }
  562. if (phBindingHandle != NULL) {
  563. if (hMachine == NULL) {
  564. //-------------------------------------------------------
  565. // Retrieve Binding Handle for the local machine
  566. //-------------------------------------------------------
  567. EnterCriticalSection(&BindingCriticalSection);
  568. if (hLocalBindingHandle != NULL) {
  569. //
  570. // local binding handle has already been set
  571. //
  572. *phBindingHandle = hLocalBindingHandle;
  573. } else {
  574. //
  575. // first time, explicitly force binding to local machine
  576. //
  577. pnp_handle = PNP_HANDLE_bind(NULL); // set rpc global
  578. if (pnp_handle == NULL) {
  579. bStatus = FALSE;
  580. *phBindingHandle = NULL;
  581. KdPrintEx((DPFLTR_PNPMGR_ID,
  582. DBGF_ERRORS,
  583. "CFGMGR32: failed to initialize local binding handle\n"));
  584. goto Clean0;
  585. }
  586. *phBindingHandle = hLocalBindingHandle = (PVOID)pnp_handle;
  587. }
  588. LeaveCriticalSection(&BindingCriticalSection);
  589. } else {
  590. //-------------------------------------------------------
  591. // Retrieve Binding Handle for the remote machine
  592. //-------------------------------------------------------
  593. //
  594. // validate the machine handle.
  595. //
  596. if (((PPNP_MACHINE)hMachine)->ulSignature != (ULONG)MACHINE_HANDLE_SIGNATURE) {
  597. bStatus = FALSE;
  598. goto Clean0;
  599. }
  600. //
  601. // use information within the hMachine handle to set the
  602. // binding handle. The hMachine info was set on a previous call
  603. // to CM_Connect_Machine.
  604. //
  605. *phBindingHandle = ((PPNP_MACHINE)hMachine)->hBindingHandle;
  606. }
  607. }
  608. Clean0:
  609. NOTHING;
  610. } except(EXCEPTION_EXECUTE_HANDLER) {
  611. bStatus = FALSE;
  612. }
  613. return bStatus;
  614. } // PnpGetGlobalHandles
  615. BOOL
  616. EnablePnPPrivileges(
  617. VOID
  618. )
  619. /*++
  620. Routine Description:
  621. This routine attempts to enable the SE_LOAD_DRIVER_NAME and SE_UNDOCK_NAME
  622. privileges in either the thread token or the calling thread (if
  623. impersonating), or thread's process token if no thread token exists.
  624. Arguments:
  625. None.
  626. Return value:
  627. Returns TRUE if successful, FALSE otherwise.
  628. Notes:
  629. Note that this routine can return successfully even if either the
  630. SE_LOAD_DRIVER_NAME or SE_UNDOCK_NAME (or both) privileges were not
  631. successfully enabled in the appropriate token.
  632. If sucessful, to determine whether the function adjusted all of the
  633. specified privileges, call GetLastError to determine the last error set by
  634. AdjustTokenPrivileges, which returns one of the following values when the
  635. function succeeds:
  636. ERROR_SUCCESS - The function adjusted all specified privileges.
  637. ERROR_NOT_ALL_ASSIGNED - The token does not have one or more of the
  638. privileges enabled.
  639. --*/
  640. {
  641. HANDLE hToken;
  642. PTOKEN_PRIVILEGES lpTokenPrivs;
  643. BOOL bSuccess;
  644. if (gLuidLoadDriverPrivilege.LowPart == 0 &&
  645. gLuidLoadDriverPrivilege.HighPart == 0) {
  646. bSuccess = LookupPrivilegeValue( NULL,
  647. SE_LOAD_DRIVER_NAME,
  648. &gLuidLoadDriverPrivilege);
  649. if (!bSuccess) {
  650. KdPrintEx((DPFLTR_PNPMGR_ID,
  651. DBGF_ERRORS,
  652. "CFGMGR32: LookupPrivilegeValue failed, error = %d\n",
  653. GetLastError()));
  654. return FALSE;
  655. }
  656. }
  657. if (gLuidUndockPrivilege.LowPart == 0 && gLuidUndockPrivilege.HighPart == 0) {
  658. bSuccess = LookupPrivilegeValue( NULL,
  659. SE_UNDOCK_NAME,
  660. &gLuidUndockPrivilege);
  661. if (!bSuccess) {
  662. KdPrintEx((DPFLTR_PNPMGR_ID,
  663. DBGF_ERRORS,
  664. "CFGMGR32: LookupPrivilegeValue failed, error = %d\n",
  665. GetLastError()));
  666. return FALSE;
  667. }
  668. }
  669. if (!OpenThreadToken(GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES, TRUE, &hToken)) {
  670. if (GetLastError() == ERROR_NO_TOKEN) {
  671. if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken)) {
  672. KdPrintEx((DPFLTR_PNPMGR_ID,
  673. DBGF_ERRORS,
  674. "CFGMGR32: OpenProcessToken returned %d\n",
  675. GetLastError()));
  676. return FALSE;
  677. }
  678. } else {
  679. KdPrintEx((DPFLTR_PNPMGR_ID,
  680. DBGF_ERRORS,
  681. "CFGMGR32: OpenThreadToken returned %d\n",
  682. GetLastError()));
  683. return FALSE;
  684. }
  685. }
  686. lpTokenPrivs = pSetupMalloc(sizeof(TOKEN_PRIVILEGES) + sizeof(LUID_AND_ATTRIBUTES));
  687. if (lpTokenPrivs == NULL) {
  688. CloseHandle(hToken);
  689. return FALSE;
  690. }
  691. lpTokenPrivs->PrivilegeCount = 2;
  692. lpTokenPrivs->Privileges[0].Luid = gLuidLoadDriverPrivilege;
  693. lpTokenPrivs->Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
  694. lpTokenPrivs->Privileges[1].Luid = gLuidUndockPrivilege;
  695. lpTokenPrivs->Privileges[1].Attributes = SE_PRIVILEGE_ENABLED;
  696. bSuccess = AdjustTokenPrivileges( hToken,
  697. FALSE, // DisableAllPrivileges
  698. lpTokenPrivs,
  699. 0,
  700. (PTOKEN_PRIVILEGES) NULL,
  701. (PDWORD) NULL);
  702. if (!bSuccess) {
  703. KdPrintEx((DPFLTR_PNPMGR_ID,
  704. DBGF_ERRORS,
  705. "CFGMGR32: AdjustTokenPrivileges failed: %u\n",
  706. GetLastError()));
  707. }
  708. pSetupFree(lpTokenPrivs);
  709. CloseHandle(hToken);
  710. return bSuccess;
  711. } // EnablePnPPrivileges
  712. BOOL
  713. IsRemoteServiceRunning(
  714. IN LPCWSTR UNCServerName,
  715. IN LPCWSTR ServiceName
  716. )
  717. /*++
  718. Routine Description:
  719. This routine connects to the active service database of the Service Control
  720. Manager (SCM) on the machine specified and returns whether or not the
  721. specified service is running.
  722. Arguments:
  723. UNCServerName - Specifies the name of the remote machine.
  724. ServiceName - Specifies the name of the service whose status is to be
  725. queried.
  726. Return value:
  727. Returns TRUE if the specified service is installed on the remote machine and
  728. is currently in the SERVICE_RUNNING state, FALSE otherwise.
  729. --*/
  730. {
  731. BOOL Status = FALSE;
  732. SC_HANDLE hSCManager = NULL, hService = NULL;
  733. SERVICE_STATUS ServiceStatus;
  734. //
  735. // Open the Service Control Manager
  736. //
  737. hSCManager = OpenSCManager(
  738. UNCServerName, // computer name
  739. SERVICES_ACTIVE_DATABASE, // SCM database name
  740. SC_MANAGER_CONNECT // access type
  741. );
  742. if (hSCManager == NULL) {
  743. KdPrintEx((DPFLTR_PNPMGR_ID,
  744. DBGF_WARNINGS,
  745. "CFGMGR32: OpenSCManager failed, error = %d\n",
  746. GetLastError()));
  747. return FALSE;
  748. }
  749. //
  750. // Open the service
  751. //
  752. hService = OpenService(
  753. hSCManager, // handle to SCM database
  754. ServiceName, // service name
  755. SERVICE_QUERY_STATUS // access type
  756. );
  757. if (hService == NULL) {
  758. Status = FALSE;
  759. KdPrintEx((DPFLTR_PNPMGR_ID,
  760. DBGF_WARNINGS,
  761. "CFGMGR32: OpenService failed, error = %d\n",
  762. GetLastError()));
  763. goto Clean0;
  764. }
  765. //
  766. // Query the service status
  767. //
  768. if (!QueryServiceStatus(hService,
  769. &ServiceStatus)) {
  770. Status = FALSE;
  771. KdPrintEx((DPFLTR_PNPMGR_ID,
  772. DBGF_WARNINGS,
  773. "CFGMGR32: QueryServiceStatus failed, error = %d\n",
  774. GetLastError()));
  775. goto Clean0;
  776. }
  777. //
  778. // Check if the service is running.
  779. //
  780. if (ServiceStatus.dwCurrentState == SERVICE_RUNNING) {
  781. Status = TRUE;
  782. }
  783. Clean0:
  784. if (hService) {
  785. CloseServiceHandle(hService);
  786. }
  787. if (hSCManager) {
  788. CloseServiceHandle(hSCManager);
  789. }
  790. return Status;
  791. } // IsRemoteServiceRunning