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.

1004 lines
25 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. testserv.c
  5. Abstract:
  6. This is a test program for exercising the service controller. This
  7. program acts like a service and exercises the Service Controller API
  8. that can be called from a service:
  9. NetServiceStartCtrlDispatcher
  10. NetServiceRegisterCtrlHandler
  11. NetServiceStatus
  12. Author:
  13. Dan Lafferty (danl) 12 Apr-1991
  14. Environment:
  15. User Mode -Win32
  16. Notes:
  17. optional-notes
  18. Revision History:
  19. --*/
  20. //
  21. // Includes
  22. //
  23. #define UNICODE 1
  24. #include <nt.h> // DbgPrint prototype
  25. #include <ntrtl.h> // DbgPrint prototype
  26. #include <windef.h>
  27. #include <nturtl.h> // needed for winbase.h
  28. #include <winbase.h>
  29. #include <winsvc.h>
  30. #include <winuser.h> // MessageBox
  31. #include <tstr.h> // Unicode string macros
  32. #include <lmcons.h> // NET_API_STATUS for srvann.h
  33. //#include <srvann.h> // I_ScSetServiceBits
  34. #include <lmserver.h> // SV_TYPE_WORKSTATION, SetServiceBits
  35. //
  36. // Defines
  37. //
  38. #define PRIVILEGE_BUF_SIZE 512
  39. #define INFINITE_WAIT_TIME 0xffffffff
  40. #define NULL_STRING TEXT("");
  41. //
  42. // Macros
  43. //
  44. #define SET_LKG_ENV_VAR(pString) \
  45. { \
  46. NTSTATUS NtStatus; \
  47. UNICODE_STRING Name,Value; \
  48. \
  49. RtlInitUnicodeString(&Name, L"LastKnownGood"); \
  50. RtlInitUnicodeString(&Value,pString); \
  51. \
  52. NtStatus = NtSetSystemEnvironmentValue(&Name,&Value); \
  53. if (!NT_SUCCESS(NtStatus)) { \
  54. DbgPrint("Failed to set LKG environment variable 0x%lx\n",NtStatus); \
  55. } \
  56. status = RtlNtStatusToDosError(NtStatus); \
  57. }
  58. //
  59. // Globals
  60. //
  61. SERVICE_STATUS MsgrStatus;
  62. SERVICE_STATUS SmfStaStatus;
  63. SERVICE_STATUS LogonStatus;
  64. HANDLE MessingerDoneEvent;
  65. HANDLE WorkstationDoneEvent;
  66. HANDLE LogonDoneEvent;
  67. SERVICE_STATUS_HANDLE MsgrStatusHandle;
  68. SERVICE_STATUS_HANDLE SmfStaStatusHandle;
  69. SERVICE_STATUS_HANDLE LogonStatusHandle;
  70. //
  71. // Function Prototypes
  72. //
  73. DWORD
  74. MessingerStart (
  75. DWORD argc,
  76. LPTSTR *argv
  77. );
  78. DWORD
  79. SmerfStationStart (
  80. DWORD argc,
  81. LPTSTR *argv
  82. );
  83. DWORD
  84. LogonStart (
  85. DWORD argc,
  86. LPTSTR *argv
  87. );
  88. VOID
  89. MsgrCtrlHandler (
  90. IN DWORD opcode
  91. );
  92. VOID
  93. SmfStaCtrlHandler (
  94. IN DWORD opcode
  95. );
  96. VOID
  97. LogonCtrlHandler (
  98. IN DWORD opcode
  99. );
  100. DWORD
  101. ScReleasePrivilege(
  102. VOID
  103. );
  104. DWORD
  105. ScGetPrivilege(
  106. IN DWORD numPrivileges,
  107. IN PULONG pulPrivileges
  108. );
  109. /****************************************************************************/
  110. VOID __cdecl
  111. main(VOID)
  112. {
  113. DWORD status;
  114. SERVICE_TABLE_ENTRY DispatchTable[] = {
  115. { TEXT("messinger"), MessingerStart },
  116. { TEXT("smerfstation"), SmerfStationStart },
  117. { TEXT("logon"), LogonStart },
  118. { NULL, NULL }
  119. };
  120. status = StartServiceCtrlDispatcher( DispatchTable);
  121. DbgPrint("The Service Process is Terminating....\n");
  122. ExitProcess(0);
  123. }
  124. /****************************************************************************/
  125. DWORD
  126. MessingerStart (
  127. DWORD argc,
  128. LPTSTR *argv
  129. )
  130. {
  131. DWORD status;
  132. DWORD i;
  133. DbgPrint(" [MESSINGER] Inside the Messinger Service Thread\n");
  134. for (i=0; i<argc; i++) {
  135. DbgPrint(" [MESSINGER] CommandArg%d = %s\n", i,argv[i]);
  136. }
  137. MessingerDoneEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
  138. //
  139. // Fill in this services status structure
  140. //
  141. MsgrStatus.dwServiceType = SERVICE_WIN32;
  142. MsgrStatus.dwCurrentState = SERVICE_RUNNING;
  143. MsgrStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
  144. MsgrStatus.dwWin32ExitCode = 0;
  145. MsgrStatus.dwServiceSpecificExitCode = 0;
  146. MsgrStatus.dwCheckPoint = 0;
  147. MsgrStatus.dwWaitHint = 0;
  148. //
  149. // Register the Control Handler routine.
  150. //
  151. DbgPrint(" [MESSINGER] Getting Ready to call NetServiceRegisterControlHandler\n");
  152. MsgrStatusHandle = RegisterServiceCtrlHandler(
  153. TEXT("messinger"),
  154. MsgrCtrlHandler);
  155. if (MsgrStatusHandle == (SERVICE_STATUS_HANDLE)0) {
  156. DbgPrint(" [MESSINGER] RegisterServiceCtrlHandler failed %d\n", GetLastError());
  157. }
  158. //
  159. // Return the status
  160. //
  161. if (!SetServiceStatus (MsgrStatusHandle, &MsgrStatus)) {
  162. status = GetLastError();
  163. DbgPrint(" [MESSINGER] SetServiceStatus error %ld\n",status);
  164. }
  165. //
  166. // SERVER ANNOUNCEMENT LOOP
  167. //
  168. do {
  169. //
  170. // Ask the user if we should clear the server announcement bits.
  171. //
  172. status = MessageBox(
  173. NULL,
  174. L"Press YES to Set Server Announcement Bits\n"
  175. L"Press NO to Clear Server Announcement Bits\n"
  176. L"Press CANCEL to sleep until shutdown",
  177. L"MESSINGER SERVICE",
  178. MB_YESNOCANCEL);
  179. DbgPrint("MessageBox return status = %d\n",status);
  180. switch(status){
  181. case IDNO:
  182. //
  183. // Register Server Announcement bits
  184. //
  185. DbgPrint(" [MESSINGER] clearing server announcement bits SV_TYPE_WORKSTATION\n");
  186. if (!SetServiceBits(MsgrStatusHandle, SV_TYPE_WORKSTATION, FALSE, FALSE)) {
  187. DbgPrint(" [MESSINGER] SetServiceBits FAILED %d\n", GetLastError());
  188. }
  189. else {
  190. DbgPrint(" [MESSINGER] SetServiceBits SUCCESS\n");
  191. }
  192. DbgPrint(" [MESSINGER] clearing server announcement bits SV_TYPE_SQLSERVER\n");
  193. if (!SetServiceBits(MsgrStatusHandle, SV_TYPE_SQLSERVER, FALSE, FALSE)) {
  194. DbgPrint(" [MESSINGER] SetServiceBits FAILED %d\n", GetLastError());
  195. }
  196. else {
  197. DbgPrint(" [MESSINGER] SetServiceBits SUCCESS\n");
  198. }
  199. break;
  200. case IDYES:
  201. //
  202. // Register Server Announcement bits
  203. //
  204. DbgPrint(" [MESSINGER] setting server announcement bits SV_TYPE_WORKSTATION\n");
  205. if (!SetServiceBits(MsgrStatusHandle, SV_TYPE_WORKSTATION, TRUE, TRUE)) {
  206. DbgPrint(" [MESSINGER] SetServiceBits FAILED %d\n", GetLastError());
  207. }
  208. else {
  209. DbgPrint(" [MESSINGER] SetServiceBits SUCCESS\n");
  210. }
  211. DbgPrint(" [MESSINGER] setting server announcement bits SV_TYPE_SQLSERVER\n");
  212. if (!SetServiceBits(MsgrStatusHandle, SV_TYPE_SQLSERVER, TRUE, TRUE)) {
  213. DbgPrint(" [MESSINGER] SetServiceBits FAILED %d\n", GetLastError());
  214. }
  215. else {
  216. DbgPrint(" [MESSINGER] SetServiceBits SUCCESS\n");
  217. }
  218. break;
  219. case IDCANCEL:
  220. break;
  221. }
  222. } while (status != IDCANCEL);
  223. //
  224. // Wait forever until we are told to terminate.
  225. //
  226. status = WaitForSingleObject (
  227. MessingerDoneEvent,
  228. INFINITE_WAIT_TIME);
  229. DbgPrint(" [MESSINGER] Leaving the messinger service\n");
  230. ExitThread(NO_ERROR);
  231. return(NO_ERROR);
  232. }
  233. /****************************************************************************/
  234. VOID
  235. MsgrCtrlHandler (
  236. IN DWORD Opcode
  237. )
  238. {
  239. DWORD status;
  240. DbgPrint(" [MESSINGER] opcode = %ld\n", Opcode);
  241. //
  242. // Find and operate on the request.
  243. //
  244. switch(Opcode) {
  245. case SERVICE_CONTROL_PAUSE:
  246. MsgrStatus.dwCurrentState = SERVICE_PAUSED;
  247. break;
  248. case SERVICE_CONTROL_CONTINUE:
  249. MsgrStatus.dwCurrentState = SERVICE_RUNNING;
  250. break;
  251. case SERVICE_CONTROL_STOP:
  252. MsgrStatus.dwWin32ExitCode = 0;
  253. MsgrStatus.dwCurrentState = SERVICE_STOPPED;
  254. SetEvent(MessingerDoneEvent);
  255. break;
  256. case SERVICE_CONTROL_INTERROGATE:
  257. break;
  258. default:
  259. DbgPrint(" [MESSINGER] Unrecognized opcode %ld\n", Opcode);
  260. }
  261. //
  262. // Send a status response.
  263. //
  264. if (!SetServiceStatus (MsgrStatusHandle, &MsgrStatus)) {
  265. status = GetLastError();
  266. DbgPrint(" [MESSINGER] SetServiceStatus error %ld\n",status);
  267. }
  268. return;
  269. }
  270. /****************************************************************************/
  271. DWORD
  272. SmerfStationStart (
  273. DWORD argc,
  274. LPTSTR *argv
  275. )
  276. {
  277. DWORD status;
  278. DWORD i;
  279. ULONG privileges[1];
  280. UNICODE_STRING valueString;
  281. NTSTATUS ntStatus;
  282. WCHAR VariableValue[64];
  283. USHORT ValueLength = 60;
  284. USHORT ReturnLength;
  285. DbgPrint(" [SMERFSTATION] Inside the Workstation Service Thread\n");
  286. for (i=0; i<argc; i++) {
  287. DbgPrint(" [SMERFSTATION] CommandArg%d = %s\n", i,argv[i]);
  288. }
  289. WorkstationDoneEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
  290. //
  291. // Fill in this services status structure
  292. //
  293. SmfStaStatus.dwServiceType = SERVICE_WIN32;
  294. SmfStaStatus.dwCurrentState = SERVICE_RUNNING;
  295. SmfStaStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP |
  296. SERVICE_ACCEPT_PAUSE_CONTINUE;
  297. SmfStaStatus.dwWin32ExitCode = 0;
  298. SmfStaStatus.dwServiceSpecificExitCode = 0;
  299. SmfStaStatus.dwCheckPoint = 0;
  300. SmfStaStatus.dwWaitHint = 0;
  301. //
  302. // Register the Control Handler routine.
  303. //
  304. DbgPrint(" [SMERFSTATION] Getting Ready to call NetServiceRegisterControlHandler\n");
  305. SmfStaStatusHandle = RegisterServiceCtrlHandler(
  306. TEXT("smerfstation"),
  307. SmfStaCtrlHandler);
  308. if (SmfStaStatusHandle == (SERVICE_STATUS_HANDLE)0) {
  309. DbgPrint(" [SMERFSTATION] RegisterServiceCtrlHandler failed %d\n", GetLastError());
  310. }
  311. //
  312. // Return the status
  313. //
  314. if (!SetServiceStatus (SmfStaStatusHandle, &SmfStaStatus)) {
  315. status = GetLastError();
  316. DbgPrint(" [SMERFSTATION] SetServiceStatus error %ld\n",status);
  317. }
  318. //
  319. // This gets SE_SECURITY_PRIVILEGE for copying security
  320. // descriptors and deleting keys.
  321. //
  322. privileges[0] = SE_SYSTEM_ENVIRONMENT_PRIVILEGE;
  323. status = ScGetPrivilege( 1, privileges);
  324. if (status != NO_ERROR) {
  325. DbgPrint("ScGetPrivilege Failed %d\n",status);
  326. }
  327. //
  328. //
  329. //
  330. do {
  331. RtlInitUnicodeString(&valueString, L"LastKnownGood");
  332. ValueLength = 60;
  333. ntStatus = NtQuerySystemEnvironmentValue(
  334. &valueString,
  335. (PWSTR)&VariableValue,
  336. ValueLength,
  337. &ReturnLength);
  338. if (!NT_SUCCESS(ntStatus)) {
  339. DbgPrint("NtQuerySystemEnvironmentValue Failure %x\n",
  340. ntStatus);
  341. }
  342. else {
  343. DbgPrint("LKG ENV VALUE = %ws\n",VariableValue);
  344. }
  345. status = MessageBox(
  346. NULL,
  347. L"Press YES to set LastKnownGood Environment Variable\n"
  348. L"Press NO to clear LastKnownGood Environment Variable\n"
  349. L"Press CANCEL to leave this loop",
  350. L"SMERFSTATION SERVICE",
  351. MB_YESNOCANCEL);
  352. DbgPrint("MessageBox return status = %d\n",status);
  353. switch (status) {
  354. case IDNO:
  355. //
  356. // Set the LKG environment variable to FALSE - so Phase 2
  357. // does not automatically revert again.
  358. //
  359. SET_LKG_ENV_VAR(L"False");
  360. break;
  361. case IDYES:
  362. //
  363. // Set the LKG environment variable to True - so Phase 2
  364. // will automatically revert, or put up the screen asking if the
  365. // user wants to revert.
  366. //
  367. SET_LKG_ENV_VAR(L"True");
  368. break;
  369. case IDCANCEL:
  370. break;
  371. }
  372. } while (status != IDCANCEL);
  373. //
  374. // Wait for the user to tell us to terminate the process.
  375. //
  376. status = MessageBox(
  377. NULL,
  378. L"Terminate testserve.exe (smerfstation, Messinger,Logon)?",
  379. L"SMERFSTATION SERVICE",
  380. MB_OK);
  381. DbgPrint("MessageBox return status = %d\n",status);
  382. if (status == IDOK) {
  383. ExitProcess(0);
  384. }
  385. status = WaitForSingleObject (
  386. WorkstationDoneEvent,
  387. INFINITE_WAIT_TIME);
  388. DbgPrint(" [SMERFSTATION] Leaving the smerfstation service\n");
  389. ExitThread(NO_ERROR);
  390. return(NO_ERROR);
  391. }
  392. /****************************************************************************/
  393. VOID
  394. SmfStaCtrlHandler (
  395. IN DWORD Opcode
  396. )
  397. {
  398. DWORD status;
  399. DbgPrint(" [SMERFSTATION] opcode = %ld\n", Opcode);
  400. //
  401. // Find and operate on the request.
  402. //
  403. switch(Opcode) {
  404. case SERVICE_CONTROL_PAUSE:
  405. SmfStaStatus.dwCurrentState = SERVICE_PAUSED;
  406. break;
  407. case SERVICE_CONTROL_CONTINUE:
  408. SmfStaStatus.dwCurrentState = SERVICE_RUNNING;
  409. break;
  410. case SERVICE_CONTROL_STOP:
  411. SmfStaStatus.dwWin32ExitCode = 0;
  412. SmfStaStatus.dwCurrentState = SERVICE_STOPPED;
  413. SetEvent(WorkstationDoneEvent);
  414. break;
  415. case SERVICE_CONTROL_INTERROGATE:
  416. break;
  417. default:
  418. DbgPrint(" [SMERFSTATION] Unrecognized opcode %ld\n", Opcode);
  419. }
  420. //
  421. // Send a status response.
  422. //
  423. if (!SetServiceStatus (SmfStaStatusHandle, &SmfStaStatus)) {
  424. status = GetLastError();
  425. DbgPrint(" [SMERFSTATION] SetServiceStatus error %ld\n",status);
  426. }
  427. return;
  428. }
  429. /****************************************************************************/
  430. DWORD
  431. LogonStart (
  432. DWORD argc,
  433. LPTSTR *argv
  434. )
  435. {
  436. DWORD status;
  437. DWORD i;
  438. DbgPrint(" [LOGON] Inside the Logon Service Thread\n");
  439. for (i=0; i<argc; i++) {
  440. DbgPrint(" [LOGON] CommandArg%d = %s\n", i,argv[i]);
  441. }
  442. LogonDoneEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
  443. //
  444. // Fill in this services status structure
  445. //
  446. LogonStatus.dwServiceType = SERVICE_WIN32;
  447. LogonStatus.dwCurrentState = SERVICE_RUNNING;
  448. LogonStatus.dwControlsAccepted = SERVICE_ACCEPT_PAUSE_CONTINUE;
  449. LogonStatus.dwWin32ExitCode = 0;
  450. LogonStatus.dwServiceSpecificExitCode = 0;
  451. LogonStatus.dwCheckPoint = 0;
  452. LogonStatus.dwWaitHint = 0;
  453. //
  454. // Register the Control Handler routine.
  455. //
  456. DbgPrint(" [LOGON] Getting Ready to call NetServiceRegisterControlHandler\n");
  457. LogonStatusHandle = RegisterServiceCtrlHandler(
  458. TEXT("logon"),
  459. LogonCtrlHandler);
  460. if (LogonStatusHandle == (SERVICE_STATUS_HANDLE)0) {
  461. DbgPrint(" [LOGON] RegisterServiceCtrlHandler failed %d\n", GetLastError());
  462. }
  463. //
  464. // Return the status
  465. //
  466. if (!SetServiceStatus (LogonStatusHandle, &LogonStatus)) {
  467. status = GetLastError();
  468. DbgPrint(" [LOGON] SetServiceStatus error %ld\n",status);
  469. }
  470. //
  471. // SERVER ANNOUNCEMENT LOOP
  472. //
  473. do {
  474. //
  475. // Ask the user if we should clear the server announcement bits.
  476. //
  477. status = MessageBox(
  478. NULL,
  479. L"Press YES to Set Server Announcement Bits\n"
  480. L"Press NO to Clear Server Announcement Bits\n"
  481. L"Press CANCEL to sleep until shutdown",
  482. L"LOGON SERVICE",
  483. MB_YESNOCANCEL);
  484. DbgPrint("MessageBox return status = %d\n",status);
  485. switch(status){
  486. case IDNO:
  487. //
  488. // Register Server Announcement bits
  489. //
  490. DbgPrint(" [LOGON] clearing server announcement bits 0x20000000\n");
  491. if (!SetServiceBits(LogonStatusHandle, 0x20000000, FALSE, TRUE)) {
  492. DbgPrint(" [LOGON] SetServiceBits FAILED\n", GetLastError());
  493. }
  494. else {
  495. DbgPrint(" [LOGON] SetServiceBits SUCCESS\n");
  496. }
  497. break;
  498. case IDYES:
  499. //
  500. // Register Server Announcement bits
  501. //
  502. DbgPrint(" [LOGON] setting server announcement bits 0x20000000\n");
  503. if (!SetServiceBits(LogonStatusHandle, 0x20000000, TRUE, TRUE)) {
  504. DbgPrint(" [LOGON] SetServiceBits FAILED\n", GetLastError());
  505. }
  506. else {
  507. DbgPrint(" [LOGON] SetServiceBits SUCCESS\n");
  508. }
  509. break;
  510. case IDCANCEL:
  511. break;
  512. }
  513. } while (status != IDCANCEL);
  514. //
  515. // Wait forever until we are told to terminate.
  516. //
  517. status = WaitForSingleObject (
  518. LogonDoneEvent,
  519. INFINITE_WAIT_TIME);
  520. DbgPrint(" [LOGON] Leaving the logon service\n");
  521. ExitThread(NO_ERROR);
  522. return(NO_ERROR);
  523. }
  524. /****************************************************************************/
  525. VOID
  526. LogonCtrlHandler (
  527. IN DWORD Opcode
  528. )
  529. {
  530. DWORD status;
  531. DbgPrint(" [LOGON] opcode = %ld\n", Opcode);
  532. //
  533. // Find and operate on the request.
  534. //
  535. switch(Opcode) {
  536. case SERVICE_CONTROL_PAUSE:
  537. LogonStatus.dwCurrentState = SERVICE_PAUSED;
  538. break;
  539. case SERVICE_CONTROL_CONTINUE:
  540. LogonStatus.dwCurrentState = SERVICE_RUNNING;
  541. break;
  542. case SERVICE_CONTROL_STOP:
  543. LogonStatus.dwWin32ExitCode = 0;
  544. LogonStatus.dwCurrentState = SERVICE_STOPPED;
  545. SetEvent(LogonDoneEvent);
  546. break;
  547. case SERVICE_CONTROL_INTERROGATE:
  548. break;
  549. default:
  550. DbgPrint(" [LOGON] Unrecognized opcode %ld\n", Opcode);
  551. }
  552. //
  553. // Send a status response.
  554. //
  555. if (!SetServiceStatus (LogonStatusHandle, &LogonStatus)) {
  556. status = GetLastError();
  557. DbgPrint(" [LOGON] SetServiceStatus error %ld\n",status);
  558. }
  559. return;
  560. }
  561. DWORD
  562. ScGetPrivilege(
  563. IN DWORD numPrivileges,
  564. IN PULONG pulPrivileges
  565. )
  566. /*++
  567. Routine Description:
  568. This function alters the privilege level for the current thread.
  569. It does this by duplicating the token for the current thread, and then
  570. applying the new privileges to that new token, then the current thread
  571. impersonates with that new token.
  572. Privileges can be relinquished by calling ScReleasePrivilege().
  573. Arguments:
  574. numPrivileges - This is a count of the number of privileges in the
  575. array of privileges.
  576. pulPrivileges - This is a pointer to the array of privileges that are
  577. desired. This is an array of ULONGs.
  578. Return Value:
  579. NO_ERROR - If the operation was completely successful.
  580. Otherwise, it returns mapped return codes from the various NT
  581. functions that are called.
  582. --*/
  583. {
  584. DWORD status;
  585. NTSTATUS ntStatus;
  586. HANDLE ourToken;
  587. HANDLE newToken;
  588. OBJECT_ATTRIBUTES Obja;
  589. SECURITY_QUALITY_OF_SERVICE SecurityQofS;
  590. ULONG bufLen;
  591. ULONG returnLen;
  592. PTOKEN_PRIVILEGES pPreviousState;
  593. PTOKEN_PRIVILEGES pTokenPrivilege = NULL;
  594. DWORD i;
  595. //
  596. // Initialize the Privileges Structure
  597. //
  598. pTokenPrivilege = (PTOKEN_PRIVILEGES) LocalAlloc(
  599. LMEM_FIXED,
  600. sizeof(TOKEN_PRIVILEGES) +
  601. (sizeof(LUID_AND_ATTRIBUTES) *
  602. numPrivileges)
  603. );
  604. if (pTokenPrivilege == NULL) {
  605. status = GetLastError();
  606. DbgPrint("ScGetPrivilege:LocalAlloc Failed %d\n", status);
  607. return(status);
  608. }
  609. pTokenPrivilege->PrivilegeCount = numPrivileges;
  610. for (i=0; i<numPrivileges ;i++ ) {
  611. pTokenPrivilege->Privileges[i].Luid = RtlConvertLongToLargeInteger(
  612. pulPrivileges[i]);
  613. pTokenPrivilege->Privileges[i].Attributes = SE_PRIVILEGE_ENABLED;
  614. }
  615. //
  616. // Initialize Object Attribute Structure.
  617. //
  618. InitializeObjectAttributes(&Obja,NULL,0L,NULL,NULL);
  619. //
  620. // Initialize Security Quality Of Service Structure
  621. //
  622. SecurityQofS.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
  623. SecurityQofS.ImpersonationLevel = SecurityImpersonation;
  624. SecurityQofS.ContextTrackingMode = FALSE; // Snapshot client context
  625. SecurityQofS.EffectiveOnly = FALSE;
  626. Obja.SecurityQualityOfService = &SecurityQofS;
  627. //
  628. // Allocate storage for the structure that will hold the Previous State
  629. // information.
  630. //
  631. pPreviousState = (PTOKEN_PRIVILEGES) LocalAlloc(
  632. LMEM_FIXED,
  633. PRIVILEGE_BUF_SIZE
  634. );
  635. if (pPreviousState == NULL) {
  636. status = GetLastError();
  637. DbgPrint("ScGetPrivilege: LocalAlloc Failed %d\n",
  638. status);
  639. LocalFree((HLOCAL)pTokenPrivilege);
  640. return(status);
  641. }
  642. //
  643. // Open our own Token
  644. //
  645. ntStatus = NtOpenProcessToken(
  646. NtCurrentProcess(),
  647. TOKEN_DUPLICATE,
  648. &ourToken);
  649. if (!NT_SUCCESS(ntStatus)) {
  650. DbgPrint( "ScGetPrivilege: NtOpenThreadToken Failed "
  651. "%x \n", ntStatus);
  652. LocalFree((HLOCAL)pPreviousState);
  653. LocalFree((HLOCAL)pTokenPrivilege);
  654. return(RtlNtStatusToDosError(ntStatus));
  655. }
  656. //
  657. // Duplicate that Token
  658. //
  659. ntStatus = NtDuplicateToken(
  660. ourToken,
  661. TOKEN_IMPERSONATE | TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
  662. &Obja,
  663. FALSE, // Duplicate the entire token
  664. TokenImpersonation, // TokenType
  665. &newToken); // Duplicate token
  666. if (!NT_SUCCESS(ntStatus)) {
  667. DbgPrint( "ScGetPrivilege: NtDuplicateToken Failed "
  668. "%x\n", ntStatus);
  669. LocalFree((HLOCAL)pPreviousState);
  670. LocalFree((HLOCAL)pTokenPrivilege);
  671. NtClose(ourToken);
  672. return(RtlNtStatusToDosError(ntStatus));
  673. }
  674. //
  675. // Add new privileges
  676. //
  677. bufLen = PRIVILEGE_BUF_SIZE;
  678. ntStatus = NtAdjustPrivilegesToken(
  679. newToken, // TokenHandle
  680. FALSE, // DisableAllPrivileges
  681. pTokenPrivilege, // NewState
  682. bufLen, // bufferSize for previous state
  683. pPreviousState, // pointer to previous state info
  684. &returnLen); // numBytes required for buffer.
  685. if (ntStatus == STATUS_BUFFER_TOO_SMALL) {
  686. LocalFree((HLOCAL)pPreviousState);
  687. bufLen = returnLen;
  688. pPreviousState = (PTOKEN_PRIVILEGES) LocalAlloc(
  689. LMEM_FIXED,
  690. (UINT) bufLen
  691. );
  692. ntStatus = NtAdjustPrivilegesToken(
  693. newToken, // TokenHandle
  694. FALSE, // DisableAllPrivileges
  695. pTokenPrivilege, // NewState
  696. bufLen, // bufferSize for previous state
  697. pPreviousState, // pointer to previous state info
  698. &returnLen); // numBytes required for buffer.
  699. }
  700. if (!NT_SUCCESS(ntStatus)) {
  701. DbgPrint( "ScGetPrivilege: NtAdjustPrivilegesToken Failed "
  702. "%x\n", ntStatus);
  703. LocalFree((HLOCAL)pPreviousState);
  704. LocalFree((HLOCAL)pTokenPrivilege);
  705. NtClose(ourToken);
  706. NtClose(newToken);
  707. return(RtlNtStatusToDosError(ntStatus));
  708. }
  709. //
  710. // Begin impersonating with the new token
  711. //
  712. ntStatus = NtSetInformationThread(
  713. NtCurrentThread(),
  714. ThreadImpersonationToken,
  715. (PVOID)&newToken,
  716. (ULONG)sizeof(HANDLE));
  717. if (!NT_SUCCESS(ntStatus)) {
  718. DbgPrint( "ScGetPrivilege: NtAdjustPrivilegesToken Failed "
  719. "%x\n", ntStatus);
  720. LocalFree((HLOCAL)pPreviousState);
  721. LocalFree((HLOCAL)pTokenPrivilege);
  722. NtClose(ourToken);
  723. NtClose(newToken);
  724. return(RtlNtStatusToDosError(ntStatus));
  725. }
  726. LocalFree(pPreviousState);
  727. LocalFree(pTokenPrivilege);
  728. NtClose(ourToken);
  729. NtClose(newToken);
  730. return(NO_ERROR);
  731. }
  732. DWORD
  733. ScReleasePrivilege(
  734. VOID
  735. )
  736. /*++
  737. Routine Description:
  738. This function relinquishes privileges obtained by calling ScGetPrivilege().
  739. Arguments:
  740. none
  741. Return Value:
  742. NO_ERROR - If the operation was completely successful.
  743. Otherwise, it returns mapped return codes from the various NT
  744. functions that are called.
  745. --*/
  746. {
  747. NTSTATUS ntStatus;
  748. HANDLE NewToken;
  749. //
  750. // Revert To Self.
  751. //
  752. NewToken = NULL;
  753. ntStatus = NtSetInformationThread(
  754. NtCurrentThread(),
  755. ThreadImpersonationToken,
  756. (PVOID)&NewToken,
  757. (ULONG)sizeof(HANDLE));
  758. if ( !NT_SUCCESS(ntStatus) ) {
  759. return(RtlNtStatusToDosError(ntStatus));
  760. }
  761. return(NO_ERROR);
  762. }