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.

916 lines
24 KiB

  1. /****************************************************************************
  2. Copyright (c) Microsoft Corporation 1999
  3. All rights reserved
  4. ***************************************************************************/
  5. #include <nt.h>
  6. #include <ntrtl.h>
  7. #include <nturtl.h>
  8. #include <windows.h>
  9. #include <assert.h>
  10. #include <stdio.h>
  11. #include <string.h>
  12. #include <ctype.h>
  13. #include <time.h>
  14. #include <winsock2.h>
  15. #include <ntexapi.h>
  16. #include <devioctl.h>
  17. #include <stdlib.h>
  18. #include <rccxport.h>
  19. #include "rcclib.h"
  20. #include "error.h"
  21. //
  22. // Defines for our internal memory, starting size and then buffers are grown by the increment
  23. //
  24. #define START_MEMORY_SIZE 0x100000
  25. #define MEMORY_INCREMENT 0x1000
  26. BOOL
  27. EnableDebugPriv(
  28. IN PVOID GlobalBuffer
  29. );
  30. DWORD
  31. RCCLibReportEventA(
  32. DWORD EventID,
  33. DWORD EventType,
  34. DWORD NumStrings,
  35. DWORD DataLength,
  36. LPSTR *Strings,
  37. LPVOID Data
  38. );
  39. HANDLE RCCLibSemHandle = NULL;
  40. DWORD
  41. RCCLibInit(
  42. OUT PVOID *GlobalBuffer,
  43. OUT PULONG GlobalBufferCurrentSize
  44. )
  45. {
  46. NTSTATUS Status;
  47. DWORD Error;
  48. ULONG Priority;
  49. PPROCESS_PRIORITY_CLASS PriorityClass;
  50. //
  51. // Check if another copy of this exe is running already
  52. //
  53. RCCLibSemHandle = CreateSemaphore(NULL, 1, 1, "RCCLibSem");
  54. Error = GetLastError();
  55. if (RCCLibSemHandle == NULL) {
  56. RCCLibReportEventA(ERROR_RCCLIB_CREATE_SEM_FAILED,
  57. EVENTLOG_ERROR_TYPE,
  58. 0,
  59. sizeof(DWORD),
  60. NULL,
  61. &Error
  62. );
  63. return ERROR_RCCLIB_CREATE_SEM_FAILED;
  64. }
  65. if (Error == ERROR_ALREADY_EXISTS) {
  66. CloseHandle(RCCLibSemHandle);
  67. RCCLibReportEventA(ERROR_RCCLIB_ALREADY_RUNNING,
  68. EVENTLOG_ERROR_TYPE,
  69. 0,
  70. sizeof(DWORD),
  71. NULL,
  72. &Error
  73. );
  74. return ERROR_RCCLIB_ALREADY_RUNNING;
  75. }
  76. //
  77. // Allocate memory for our buffers
  78. //
  79. *GlobalBuffer = LocalAlloc(LPTR, START_MEMORY_SIZE * sizeof(char));
  80. if (*GlobalBuffer == NULL) {
  81. CloseHandle(RCCLibSemHandle);
  82. RCCLibSemHandle = NULL;
  83. RCCLibReportEventA(ERROR_RCCLIB_INITIAL_ALLOC_FAILED,
  84. EVENTLOG_ERROR_TYPE,
  85. 0,
  86. 0,
  87. NULL,
  88. NULL
  89. );
  90. return ERROR_RCCLIB_INITIAL_ALLOC_FAILED;
  91. }
  92. *GlobalBufferCurrentSize = START_MEMORY_SIZE * sizeof(char);
  93. //
  94. // Give ourselve God access if possible
  95. //
  96. if (!EnableDebugPriv(*GlobalBuffer)) {
  97. LocalFree(*GlobalBuffer);
  98. CloseHandle(RCCLibSemHandle);
  99. RCCLibSemHandle = NULL;
  100. Error = GetLastError();
  101. RCCLibReportEventA(ERROR_RCCLIB_PRIVILEDGES_FAILED,
  102. EVENTLOG_WARNING_TYPE,
  103. 0,
  104. sizeof(DWORD),
  105. NULL,
  106. &Error
  107. );
  108. return Error;
  109. }
  110. //
  111. // Now try and bump up our priority so that we can guarantee service
  112. //
  113. PriorityClass = (PPROCESS_PRIORITY_CLASS)(*GlobalBuffer);
  114. PriorityClass = (PPROCESS_PRIORITY_CLASS)(ALIGN_UP_POINTER(PriorityClass, PROCESS_PRIORITY_CLASS));
  115. Status = NtQueryInformationProcess(NtCurrentProcess(),
  116. ProcessPriorityClass,
  117. PriorityClass,
  118. sizeof(PROCESS_PRIORITY_CLASS),
  119. NULL
  120. );
  121. if (!NT_SUCCESS(Status)) {
  122. LocalFree(*GlobalBuffer);
  123. CloseHandle(RCCLibSemHandle);
  124. RCCLibSemHandle = NULL;
  125. Error = RtlNtStatusToDosError(Status);
  126. RCCLibReportEventA(ERROR_RCCLIB_QUERY_PRIORITY_FAILED,
  127. EVENTLOG_ERROR_TYPE,
  128. 0,
  129. sizeof(DWORD),
  130. NULL,
  131. &Error
  132. );
  133. return Error;
  134. }
  135. PriorityClass->PriorityClass = PROCESS_PRIORITY_CLASS_REALTIME;
  136. Status = NtSetInformationProcess(NtCurrentProcess(),
  137. ProcessPriorityClass,
  138. PriorityClass,
  139. sizeof(PROCESS_PRIORITY_CLASS)
  140. );
  141. if (!NT_SUCCESS(Status)) {
  142. LocalFree(*GlobalBuffer);
  143. CloseHandle(RCCLibSemHandle);
  144. RCCLibSemHandle = NULL;
  145. Error = RtlNtStatusToDosError(Status);
  146. RCCLibReportEventA(ERROR_RCCLIB_SET_PRIORITY_FAILED,
  147. EVENTLOG_ERROR_TYPE,
  148. 0,
  149. sizeof(DWORD),
  150. NULL,
  151. &Error
  152. );
  153. return Error;
  154. }
  155. //
  156. // A *total* DaveC hack is that if you use ThreadBasePriority, and send
  157. // down (HIGH_PRIORITY + 1) / 2, this actually puts you at HIGH_PRIORITY
  158. // such that you cannot be bumped back down in priority... NT trivia for you.
  159. //
  160. Priority = (HIGH_PRIORITY + 1) / 2;
  161. Status = NtSetInformationThread(NtCurrentThread(),
  162. ThreadBasePriority,
  163. &Priority,
  164. sizeof(Priority)
  165. );
  166. if (!NT_SUCCESS(Status)) {
  167. //
  168. // Log an error!
  169. //
  170. Error = RtlNtStatusToDosError(Status);
  171. RCCLibReportEventA(ERROR_RCCLIB_SET_PRIORITY_FAILED,
  172. EVENTLOG_ERROR_TYPE,
  173. 0,
  174. sizeof(DWORD),
  175. NULL,
  176. &Error
  177. );
  178. return Error;
  179. }
  180. }
  181. VOID
  182. RCCLibExit(
  183. IN PVOID GlobalBuffer,
  184. IN ULONG GlobalBufferSize
  185. )
  186. {
  187. if (RCCLibSemHandle != NULL) {
  188. CloseHandle(RCCLibSemHandle);
  189. RCCLibSemHandle = NULL;
  190. }
  191. if (GlobalBuffer != NULL) {
  192. LocalFree(GlobalBuffer);
  193. }
  194. }
  195. DWORD
  196. RCCLibReportEventA(
  197. DWORD EventID,
  198. DWORD EventType,
  199. DWORD NumStrings,
  200. DWORD DataLength,
  201. LPSTR *Strings,
  202. LPVOID Data
  203. )
  204. /*++
  205. Routine Description:
  206. This function writes the specified (EventID) log at the end of the
  207. eventlog.
  208. Arguments:
  209. EventID - The specific event identifier. This identifies the
  210. message that goes with this event.
  211. EventType - Specifies the type of event being logged. This
  212. parameter can have one of the following
  213. values:
  214. Value Meaning
  215. EVENTLOG_ERROR_TYPE Error event
  216. EVENTLOG_WARNING_TYPE Warning event
  217. EVENTLOG_INFORMATION_TYPE Information event
  218. NumStrings - Specifies the number of strings that are in the array
  219. at 'Strings'. A value of zero indicates no strings
  220. are present.
  221. DataLength - Specifies the number of bytes of event-specific raw
  222. (binary) data to write to the log. If cbData is
  223. zero, no event-specific data is present.
  224. Strings - Points to a buffer containing an array of null-terminated
  225. strings that are merged into the message before
  226. displaying to the user. This parameter must be a valid
  227. pointer (or NULL), even if cStrings is zero.
  228. Data - Buffer containing the raw data. This parameter must be a
  229. valid pointer (or NULL), even if cbData is zero.
  230. Return Value:
  231. Returns the WIN32 extended error obtained by GetLastError().
  232. NOTE : This function works slow since it calls the open and close
  233. eventlog source everytime.
  234. --*/
  235. {
  236. HANDLE EventlogHandle;
  237. DWORD ReturnCode;
  238. //
  239. // open eventlog section.
  240. //
  241. EventlogHandle = RegisterEventSourceW(NULL, L"RCCLib");
  242. if (EventlogHandle == NULL) {
  243. ReturnCode = GetLastError();
  244. goto Cleanup;
  245. }
  246. //
  247. // Log the error code specified
  248. //
  249. if(!ReportEventA(EventlogHandle,
  250. (WORD)EventType,
  251. 0, // event category
  252. EventID,
  253. NULL,
  254. (WORD)NumStrings,
  255. DataLength,
  256. Strings,
  257. Data
  258. )) {
  259. ReturnCode = GetLastError();
  260. goto Cleanup;
  261. }
  262. ReturnCode = ERROR_SUCCESS;
  263. Cleanup:
  264. if (EventlogHandle != NULL) {
  265. DeregisterEventSource(EventlogHandle);
  266. }
  267. return ReturnCode;
  268. }
  269. BOOL
  270. EnableDebugPriv(
  271. IN PVOID GlobalBuffer
  272. )
  273. /*++
  274. Routine Description:
  275. Changes the process's privilige so that kill works properly.
  276. Arguments:
  277. Return Value:
  278. TRUE - success
  279. FALSE - failure
  280. --*/
  281. {
  282. HANDLE hToken;
  283. LUID DebugValue;
  284. PTOKEN_PRIVILEGES ptkp;
  285. //
  286. // Retrieve a handle of the access token
  287. //
  288. if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) {
  289. return FALSE;
  290. }
  291. //
  292. // Enable the SE_DEBUG_NAME privilege.
  293. //
  294. if (!LookupPrivilegeValue((LPSTR) NULL, SE_DEBUG_NAME, &DebugValue)) {
  295. return FALSE;
  296. }
  297. ptkp = (PTOKEN_PRIVILEGES)GlobalBuffer;
  298. ptkp->PrivilegeCount = 4;
  299. ptkp->Privileges[0].Luid = DebugValue;
  300. ptkp->Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
  301. //
  302. // Enable the INCREASE_BASE_PRIORITY privilege.
  303. //
  304. if (!LookupPrivilegeValue((LPSTR) NULL, SE_INC_BASE_PRIORITY_NAME, &DebugValue)) {
  305. return FALSE;
  306. }
  307. ptkp->Privileges[1].Luid = DebugValue;
  308. ptkp->Privileges[1].Attributes = SE_PRIVILEGE_ENABLED;
  309. //
  310. // Enable the SHUTDOWN privilege.
  311. //
  312. if (!LookupPrivilegeValue((LPSTR) NULL, SE_SHUTDOWN_NAME, &DebugValue)) {
  313. return FALSE;
  314. }
  315. ptkp->Privileges[2].Luid = DebugValue;
  316. ptkp->Privileges[2].Attributes = SE_PRIVILEGE_ENABLED;
  317. //
  318. // Enable the QUOTA privilege.
  319. //
  320. if (!LookupPrivilegeValue((LPSTR) NULL, SE_INCREASE_QUOTA_NAME, &DebugValue)) {
  321. return FALSE;
  322. }
  323. ptkp->Privileges[3].Luid = DebugValue;
  324. ptkp->Privileges[3].Attributes = SE_PRIVILEGE_ENABLED;
  325. if (!AdjustTokenPrivileges(hToken,
  326. FALSE,
  327. ptkp,
  328. sizeof(TOKEN_PRIVILEGES) + (3 * sizeof(LUID_AND_ATTRIBUTES)),
  329. (PTOKEN_PRIVILEGES) NULL,
  330. (PDWORD) NULL)) {
  331. //
  332. // The return value of AdjustTokenPrivileges be texted
  333. //
  334. return FALSE;
  335. }
  336. return TRUE;
  337. }
  338. DWORD
  339. RCCLibGetTListInfo(
  340. OUT PRCC_RSP_TLIST ResponseBuffer,
  341. IN LONG ResponseBufferSize,
  342. OUT PULONG ResponseDataSize
  343. )
  344. {
  345. DWORD Error;
  346. NTSTATUS Status;
  347. TIME_FIELDS UpTime;
  348. LARGE_INTEGER Time;
  349. PSYSTEM_PAGEFILE_INFORMATION PageFileInfo;
  350. PUCHAR DataBuffer;
  351. PUCHAR StartProcessInfo;
  352. LONG CurrentBufferSize;
  353. ULONG ReturnLength;
  354. ULONG TotalOffset;
  355. PSYSTEM_PROCESS_INFORMATION ProcessInfo;
  356. PSYSTEM_THREAD_INFORMATION ThreadInfo;
  357. *ResponseDataSize = 0;
  358. if (ResponseBufferSize < sizeof(ResponseBuffer)) {
  359. return(RtlNtStatusToDosError(STATUS_INFO_LENGTH_MISMATCH));
  360. }
  361. DataBuffer = (PUCHAR)(ResponseBuffer + 1);
  362. CurrentBufferSize = ResponseBufferSize - sizeof(RCC_RSP_TLIST);
  363. if (CurrentBufferSize < 0) {
  364. return ERROR_OUTOFMEMORY;
  365. }
  366. //
  367. // Get system-wide information
  368. //
  369. Status = NtQuerySystemInformation(SystemTimeOfDayInformation,
  370. &(ResponseBuffer->TimeOfDayInfo),
  371. sizeof(SYSTEM_TIMEOFDAY_INFORMATION),
  372. NULL
  373. );
  374. if (!NT_SUCCESS(Status)) {
  375. return(RtlNtStatusToDosError(Status));
  376. }
  377. Status = NtQuerySystemInformation(SystemBasicInformation,
  378. &(ResponseBuffer->BasicInfo),
  379. sizeof(SYSTEM_BASIC_INFORMATION),
  380. NULL
  381. );
  382. if (!NT_SUCCESS(Status)) {
  383. return(RtlNtStatusToDosError(Status));
  384. }
  385. //
  386. // Get pagefile information
  387. //
  388. PageFileInfo = (PSYSTEM_PAGEFILE_INFORMATION)DataBuffer;
  389. Status = NtQuerySystemInformation(SystemPageFileInformation,
  390. PageFileInfo,
  391. CurrentBufferSize,
  392. &ReturnLength
  393. );
  394. if (NT_SUCCESS(Status)) {
  395. ResponseBuffer->PagefileInfoOffset = ResponseBufferSize - CurrentBufferSize;
  396. CurrentBufferSize -= ReturnLength;
  397. DataBuffer += ReturnLength;
  398. if (CurrentBufferSize < 0) {
  399. return ERROR_OUTOFMEMORY;
  400. }
  401. //
  402. // Go thru each pagefile and fixup the names...
  403. //
  404. for (; ; ) {
  405. if (PageFileInfo->PageFileName.Length > CurrentBufferSize) {
  406. return(RtlNtStatusToDosError(STATUS_INFO_LENGTH_MISMATCH));
  407. }
  408. RtlCopyMemory(DataBuffer,
  409. (PUCHAR)(PageFileInfo->PageFileName.Buffer),
  410. PageFileInfo->PageFileName.Length
  411. );
  412. PageFileInfo->PageFileName.Buffer = (PWSTR)(ResponseBufferSize - CurrentBufferSize);
  413. DataBuffer += PageFileInfo->PageFileName.Length;
  414. CurrentBufferSize -= PageFileInfo->PageFileName.Length;
  415. if (CurrentBufferSize < 0) {
  416. return ERROR_OUTOFMEMORY;
  417. }
  418. if (PageFileInfo->NextEntryOffset == 0) {
  419. break;
  420. }
  421. PageFileInfo = (PSYSTEM_PAGEFILE_INFORMATION)((PCHAR)PageFileInfo + PageFileInfo->NextEntryOffset);
  422. }
  423. } else if (((ULONG)CurrentBufferSize) < ReturnLength) {
  424. return(RtlNtStatusToDosError(STATUS_INFO_LENGTH_MISMATCH));
  425. } else {
  426. ResponseBuffer->PagefileInfoOffset = 0;
  427. }
  428. //
  429. // Get process information
  430. //
  431. Status = NtQuerySystemInformation(SystemFileCacheInformation,
  432. &(ResponseBuffer->FileCache),
  433. sizeof(ResponseBuffer->FileCache),
  434. NULL
  435. );
  436. if (!NT_SUCCESS(Status)) {
  437. return(RtlNtStatusToDosError(Status));
  438. }
  439. Status = NtQuerySystemInformation(SystemPerformanceInformation,
  440. &(ResponseBuffer->PerfInfo),
  441. sizeof(ResponseBuffer->PerfInfo),
  442. NULL
  443. );
  444. if (!NT_SUCCESS(Status)) {
  445. return(RtlNtStatusToDosError(Status));
  446. }
  447. //
  448. // Realign DataBuffer for the next query
  449. //
  450. DataBuffer = ALIGN_UP_POINTER(DataBuffer, SYSTEM_PROCESS_INFORMATION);
  451. CurrentBufferSize = ResponseBufferSize - (((ULONG_PTR)DataBuffer) - ((ULONG_PTR)ResponseBuffer));
  452. if (CurrentBufferSize < 0) {
  453. return ERROR_OUTOFMEMORY;
  454. }
  455. Status = NtQuerySystemInformation(SystemProcessInformation,
  456. DataBuffer,
  457. CurrentBufferSize,
  458. &ReturnLength
  459. );
  460. if (!NT_SUCCESS(Status)) {
  461. return(RtlNtStatusToDosError(Status));
  462. }
  463. StartProcessInfo = DataBuffer;
  464. ResponseBuffer->ProcessInfoOffset = ResponseBufferSize - CurrentBufferSize;
  465. DataBuffer += ReturnLength;
  466. CurrentBufferSize -= ReturnLength;
  467. if (CurrentBufferSize < 0) {
  468. return ERROR_OUTOFMEMORY;
  469. }
  470. TotalOffset = 0;
  471. ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)StartProcessInfo;
  472. while (TRUE) {
  473. //
  474. // We have to take the name of each process and change the UNICODE_STRING to an offset, copying
  475. // the name to later in the buffer.
  476. //
  477. if (ProcessInfo->ImageName.Buffer) {
  478. if (CurrentBufferSize < ProcessInfo->ImageName.Length) {
  479. return(STATUS_INFO_LENGTH_MISMATCH);
  480. }
  481. RtlCopyMemory(DataBuffer, (PUCHAR)(ProcessInfo->ImageName.Buffer), ProcessInfo->ImageName.Length);
  482. ProcessInfo->ImageName.Buffer = (PWSTR)(ResponseBufferSize - CurrentBufferSize);
  483. DataBuffer += ProcessInfo->ImageName.Length;
  484. CurrentBufferSize -= ProcessInfo->ImageName.Length;
  485. if (CurrentBufferSize < 0) {
  486. return ERROR_OUTOFMEMORY;
  487. }
  488. }
  489. if (ProcessInfo->NextEntryOffset == 0) {
  490. break;
  491. }
  492. TotalOffset += ProcessInfo->NextEntryOffset;
  493. ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)&(StartProcessInfo[TotalOffset]);
  494. }
  495. *ResponseDataSize = (ULONG)(ResponseBufferSize - CurrentBufferSize);
  496. return ERROR_SUCCESS;
  497. }
  498. DWORD
  499. RCCLibKillProcess(
  500. DWORD ProcessId
  501. )
  502. {
  503. DWORD Error;
  504. HANDLE Handle;
  505. //
  506. // Try to open the process
  507. //
  508. Handle = OpenProcess(PROCESS_TERMINATE, FALSE, ProcessId);
  509. if (Handle == NULL) {
  510. return GetLastError();
  511. }
  512. //
  513. // Kill it
  514. //
  515. if (!TerminateProcess(Handle, 1)) {
  516. CloseHandle(Handle);
  517. return GetLastError();
  518. }
  519. //
  520. // All done
  521. //
  522. CloseHandle(Handle);
  523. return ERROR_SUCCESS;
  524. }
  525. DWORD
  526. RCCLibLowerProcessPriority(
  527. DWORD ProcessId
  528. )
  529. {
  530. DWORD Error;
  531. HANDLE JobHandle;
  532. HANDLE ProcessHandle;
  533. JOBOBJECT_EXTENDED_LIMIT_INFORMATION ProposedLimits;
  534. TCHAR NameBuffer[50];
  535. BOOLEAN CreatedJobObject;
  536. DWORD ReturnedLength;
  537. //
  538. // Create the name for the job object
  539. //
  540. sprintf(NameBuffer, "RCCSrv%d", ProcessId);
  541. //
  542. // Try and open the existing job object
  543. //
  544. JobHandle = OpenJobObject(MAXIMUM_ALLOWED, FALSE, NameBuffer);
  545. if (JobHandle == NULL) {
  546. //
  547. // Try to open the process
  548. //
  549. ProcessHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, ProcessId);
  550. if (ProcessHandle == NULL) {
  551. return GetLastError();
  552. }
  553. //
  554. // Now try and create a job object to wrap around this process.
  555. //
  556. JobHandle = CreateJobObject(NULL, NameBuffer);
  557. if (JobHandle == NULL) {
  558. CloseHandle(ProcessHandle);
  559. return GetLastError();
  560. }
  561. CreatedJobObject = TRUE;
  562. //
  563. // Assign the process to this new job object.
  564. //
  565. if (!AssignProcessToJobObject(JobHandle, ProcessHandle)) {
  566. CloseHandle(ProcessHandle);
  567. goto ErrorExit;
  568. }
  569. CloseHandle(ProcessHandle);
  570. } else {
  571. CreatedJobObject = FALSE;
  572. }
  573. //
  574. // Get the current set of limits
  575. //
  576. if (!QueryInformationJobObject(JobHandle,
  577. JobObjectExtendedLimitInformation,
  578. &ProposedLimits,
  579. sizeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION),
  580. &ReturnedLength
  581. )) {
  582. goto ErrorExit;
  583. }
  584. //
  585. // Change the scheduling class and priority fields
  586. //
  587. ProposedLimits.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_PRIORITY_CLASS;
  588. ProposedLimits.BasicLimitInformation.PriorityClass = IDLE_PRIORITY_CLASS;
  589. ProposedLimits.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_SCHEDULING_CLASS;
  590. ProposedLimits.BasicLimitInformation.SchedulingClass = 0;
  591. if (!SetInformationJobObject(JobHandle,
  592. JobObjectExtendedLimitInformation,
  593. &ProposedLimits,
  594. sizeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION)
  595. )) {
  596. goto ErrorExit;
  597. }
  598. //
  599. // All done - leave the job handle out there, so we can get to it later.
  600. //
  601. return ERROR_SUCCESS;
  602. ErrorExit:
  603. if (CreatedJobObject) {
  604. CloseHandle(JobHandle);
  605. }
  606. return GetLastError();
  607. }
  608. DWORD
  609. RCCLibLimitProcessMemory(
  610. DWORD ProcessId,
  611. DWORD MemoryLimit // in number of KB allowed
  612. )
  613. {
  614. DWORD Error;
  615. HANDLE JobHandle;
  616. HANDLE ProcessHandle;
  617. JOBOBJECT_EXTENDED_LIMIT_INFORMATION ProposedLimits;
  618. TCHAR NameBuffer[50];
  619. BOOLEAN CreatedJobObject;
  620. DWORD ReturnedLength;
  621. //
  622. // Create the name for the job object
  623. //
  624. sprintf(NameBuffer, "RCCSrv%d", ProcessId);
  625. //
  626. // Try and open the existing job object
  627. //
  628. JobHandle = OpenJobObject(MAXIMUM_ALLOWED, FALSE, NameBuffer);
  629. if (JobHandle == NULL) {
  630. //
  631. // Try to open the process
  632. //
  633. ProcessHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, ProcessId);
  634. if (ProcessHandle == NULL) {
  635. return GetLastError();
  636. }
  637. //
  638. // Now try and create a job object to wrap around this process.
  639. //
  640. JobHandle = CreateJobObject(NULL, NameBuffer);
  641. if (JobHandle == NULL) {
  642. CloseHandle(ProcessHandle);
  643. return GetLastError();
  644. }
  645. CreatedJobObject = TRUE;
  646. //
  647. // Assign the process to this new job object.
  648. //
  649. if (!AssignProcessToJobObject(JobHandle, ProcessHandle)) {
  650. CloseHandle(ProcessHandle);
  651. goto ErrorExit;
  652. }
  653. CloseHandle(ProcessHandle);
  654. } else {
  655. CreatedJobObject = FALSE;
  656. }
  657. //
  658. // Get the current set of limits
  659. //
  660. if (!QueryInformationJobObject(JobHandle,
  661. JobObjectExtendedLimitInformation,
  662. &ProposedLimits,
  663. sizeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION),
  664. &ReturnedLength
  665. )) {
  666. goto ErrorExit;
  667. }
  668. //
  669. // Change the memory limits
  670. //
  671. ProposedLimits.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_PROCESS_MEMORY;
  672. ProposedLimits.ProcessMemoryLimit = MemoryLimit * 1024 * 1024;
  673. ProposedLimits.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_JOB_MEMORY;
  674. ProposedLimits.JobMemoryLimit = MemoryLimit * 1024 * 1024;
  675. if (!SetInformationJobObject(JobHandle,
  676. JobObjectExtendedLimitInformation,
  677. &ProposedLimits,
  678. sizeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION)
  679. )) {
  680. goto ErrorExit;
  681. }
  682. //
  683. // All done - leave the job handle out there, so we can get to it later.
  684. //
  685. return ERROR_SUCCESS;
  686. ErrorExit:
  687. if (CreatedJobObject) {
  688. CloseHandle(JobHandle);
  689. }
  690. return GetLastError();
  691. }
  692. DWORD
  693. RCCLibIncreaseMemory(
  694. OUT PVOID *GlobalBuffer,
  695. OUT PULONG GlobalBufferCurrentSize
  696. )
  697. {
  698. NTSTATUS Status;
  699. PVOID NewBuffer;
  700. NewBuffer = VirtualAlloc(NULL,
  701. *GlobalBufferCurrentSize + MEMORY_INCREMENT,
  702. MEM_COMMIT,
  703. PAGE_READWRITE | PAGE_NOCACHE
  704. );
  705. if (NewBuffer == NULL) {
  706. return ERROR_OUTOFMEMORY;
  707. }
  708. VirtualFree(*GlobalBuffer, *GlobalBufferCurrentSize, MEM_DECOMMIT);
  709. *GlobalBufferCurrentSize += MEMORY_INCREMENT;
  710. *GlobalBuffer = NewBuffer;
  711. return ERROR_SUCCESS;
  712. }