Leaked source code of windows server 2003
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.

1359 lines
39 KiB

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. elfsec.c
  5. Author:
  6. Dan Hinsley (danhi) 28-Mar-1992
  7. Environment:
  8. Calls NT native APIs.
  9. Revision History:
  10. 27-Oct-1993 danl
  11. Make Eventlog service a DLL and attach it to services.exe.
  12. Removed functions that create well-known SIDs. This information
  13. is now passed into the Elfmain as a Global data structure containing
  14. all well-known SIDs.
  15. 28-Mar-1992 danhi
  16. created - based on scsec.c in svcctrl by ritaw
  17. 03-Mar-1995 markbl
  18. Added guest & anonymous logon log access restriction feature.
  19. 18-Mar-2001 a-jyotig
  20. Added clean up code to ElfpAccessCheckAndAudit to reset the
  21. g_lNumSecurityWriters to 0 in case of any error
  22. --*/
  23. #include <eventp.h>
  24. #include <elfcfg.h>
  25. #include <Psapi.h>
  26. #include <Sddl.h>
  27. #include <strsafe.h>
  28. #define PRIVILEGE_BUF_SIZE 512
  29. extern long g_lNumSecurityWriters;
  30. BOOL g_bGetClientProc = FALSE;
  31. //-------------------------------------------------------------------//
  32. // //
  33. // Local function prototypes //
  34. // //
  35. //-------------------------------------------------------------------//
  36. NTSTATUS
  37. ElfpGetPrivilege(
  38. IN DWORD numPrivileges,
  39. IN PULONG pulPrivileges
  40. );
  41. NTSTATUS
  42. ElfpReleasePrivilege(
  43. VOID
  44. );
  45. //-------------------------------------------------------------------//
  46. // //
  47. // Structure that describes the mapping of generic access rights to //
  48. // object specific access rights for a LogFile object. //
  49. // //
  50. //-------------------------------------------------------------------//
  51. static GENERIC_MAPPING LogFileObjectMapping = {
  52. STANDARD_RIGHTS_READ | // Generic read
  53. ELF_LOGFILE_READ,
  54. STANDARD_RIGHTS_WRITE | // Generic write
  55. ELF_LOGFILE_WRITE | ELF_LOGFILE_CLEAR,
  56. STANDARD_RIGHTS_EXECUTE | // Generic execute
  57. 0,
  58. ELF_LOGFILE_ALL_ACCESS // Generic all
  59. };
  60. LPWSTR
  61. GetCustomSDString(
  62. HANDLE hLogRegKey, BOOL *pbCustomSDAlreadyExists)
  63. /*++
  64. Routine Description:
  65. This function reads the SDDL security descriptor from the key. Note that it may
  66. or may not be there.
  67. Arguments:
  68. hLogFile - Handle to registry key for the log
  69. Return Value:
  70. If NULL, then the key wasnt there. Otherwise, it is a string that should be deleted
  71. via ElfpFreeBuffer
  72. --*/
  73. {
  74. // read in the optional SD
  75. DWORD dwStatus, dwType, dwSize;
  76. *pbCustomSDAlreadyExists = FALSE;
  77. if(hLogRegKey == NULL)
  78. return NULL;
  79. dwStatus = RegQueryValueExW(hLogRegKey, VALUE_CUSTOM_SD, 0, &dwType,
  80. 0, &dwSize);
  81. if (dwStatus == 0 && dwType == REG_SZ)
  82. {
  83. LPWSTR wNew;
  84. *pbCustomSDAlreadyExists = TRUE;
  85. dwSize += sizeof(WCHAR);
  86. wNew = (LPWSTR)ElfpAllocateBuffer(dwSize);
  87. if(wNew)
  88. {
  89. dwStatus = RegQueryValueEx(hLogRegKey, VALUE_CUSTOM_SD, 0, &dwType,
  90. (BYTE *)wNew, &dwSize);
  91. if (dwStatus != 0 ||dwType != REG_SZ)
  92. {
  93. ElfpFreeBuffer(wNew);
  94. }
  95. else
  96. return wNew;
  97. }
  98. }
  99. return NULL;
  100. }
  101. // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  102. // note for access rights, 1 = read, 2 = write, 4 = clear
  103. LPWSTR pOwnerAndGroup = L"O:BAG:SYD:";
  104. LPWSTR pDenyList =
  105. L"(D;;0xf0007;;;AN)" // Anonymous logon
  106. L"(D;;0xf0007;;;BG)"; // Guests
  107. LPWSTR pSecurityList =
  108. L"(A;;0xf0005;;;SY)" // local system
  109. L"(A;;0x5;;;BA)"; // built in admins
  110. LPWSTR pSystemList =
  111. L"(A;;0xf0007;;;SY)" // local system
  112. L"(A;;0x7;;;BA)" // built in admins
  113. L"(A;;0x5;;;SO)" // server operators
  114. L"(A;;0x1;;;IU)" // INTERACTIVE LOGON
  115. L"(A;;0x1;;;SU)" // SERVICES LOGON
  116. L"(A;;0x1;;;S-1-5-3)" // BATCH LOGON
  117. L"(A;;0x2;;;LS)" // local service
  118. L"(A;;0x2;;;NS)"; // network service
  119. LPWSTR pApplicationList =
  120. L"(A;;0xf0007;;;SY)" // local system
  121. L"(A;;0x7;;;BA)" // built in admins
  122. L"(A;;0x7;;;SO)" // server operators
  123. L"(A;;0x3;;;IU)" // INTERACTIVE LOGON
  124. L"(A;;0x3;;;SU)" // SERVICES LOGON
  125. L"(A;;0x3;;;S-1-5-3)"; // BATCH LOGON
  126. // L"(A;;0X3;;;S-1-5-3)"; // BATCH LOGON
  127. // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  128. LPWSTR GetDefaultSDDL(
  129. DWORD Type,
  130. HANDLE hLogRegKey
  131. )
  132. /*++
  133. Routine Description:
  134. This function is used when a log file does not have a custom security descriptor.
  135. This returns the string which should be freed by the caller via ElfpFreeBuffer.
  136. Arguments:
  137. LogFile - pointer the the LOGFILE structure for this logfile
  138. Return Value:
  139. --*/
  140. {
  141. LPWSTR pAllowList = NULL;
  142. int iLenInWCHAR = 0;
  143. LPWSTR pwszTempSDDLString = NULL;
  144. BOOL bUseDenyList;
  145. DWORD dwRestrictGuestAccess;
  146. DWORD dwSize, dwType;
  147. long lRet;
  148. // Determine the Allow list
  149. if(Type == ELF_LOGFILE_SECURITY)
  150. pAllowList = pSecurityList;
  151. else if(Type == ELF_LOGFILE_SYSTEM)
  152. pAllowList = pSystemList;
  153. else
  154. pAllowList = pApplicationList;
  155. // determine if the deny list is applicable.
  156. bUseDenyList = TRUE;
  157. // if the RestrictGuestAccess is actually set and it is 0, then dont
  158. // restrict guests.
  159. dwSize = sizeof( DWORD );
  160. if(hLogRegKey)
  161. {
  162. lRet = RegQueryValueEx( hLogRegKey, VALUE_RESTRICT_GUEST_ACCESS, NULL,
  163. &dwType, (LPBYTE)&dwRestrictGuestAccess, &dwSize);
  164. if(lRet == ERROR_SUCCESS && dwType == REG_DWORD && dwRestrictGuestAccess == 0)
  165. bUseDenyList = FALSE;
  166. }
  167. // Calculate the total length and allocate the buffer
  168. iLenInWCHAR = wcslen(pOwnerAndGroup) + 1; // one for the eventual null as well as owner
  169. if (bUseDenyList)
  170. iLenInWCHAR += wcslen(pDenyList);
  171. iLenInWCHAR += wcslen(pAllowList);
  172. pwszTempSDDLString = ElfpAllocateBuffer(iLenInWCHAR * sizeof(WCHAR));
  173. if(pwszTempSDDLString == NULL)
  174. {
  175. return NULL;
  176. }
  177. // build the strings
  178. StringCchCopy(pwszTempSDDLString, iLenInWCHAR , pOwnerAndGroup);
  179. if (bUseDenyList)
  180. StringCchCat(pwszTempSDDLString, iLenInWCHAR , pDenyList);
  181. StringCchCat(pwszTempSDDLString, iLenInWCHAR , pAllowList);
  182. return pwszTempSDDLString;
  183. }
  184. NTSTATUS ChangeStringSD(
  185. PLOGFILE LogFile,
  186. LPWSTR pwsCustomSDDL)
  187. {
  188. NTSTATUS Status;
  189. BOOL bRet;
  190. PSECURITY_DESCRIPTOR pSD;
  191. bRet = ConvertStringSecurityDescriptorToSecurityDescriptorW(
  192. pwsCustomSDDL, // security descriptor string
  193. 1, // revision level
  194. &pSD, // SD
  195. NULL
  196. );
  197. if(!bRet)
  198. {
  199. ELF_LOG2(ERROR,
  200. "ChangeStringSD: ConvertStringSDToSDW %#x\n, str = %ws\n",
  201. GetLastError(), pwsCustomSDDL);
  202. return STATUS_ACCESS_DENIED;
  203. }
  204. bRet = IsValidSecurityDescriptor(pSD);
  205. if(!bRet)
  206. {
  207. LocalFree(pSD);
  208. ELF_LOG2(ERROR,
  209. "ChangeStringSD: IsValidSecurityDescriptor %#x\n, str = %ws",
  210. GetLastError(), pwsCustomSDDL);
  211. return STATUS_ACCESS_DENIED;
  212. }
  213. // copy this into a normal Rtl allocation since we dont want to keep
  214. // track of when the SD can be freed by LocalAlloc
  215. Status = RtlCopySecurityDescriptor(
  216. pSD,
  217. &LogFile->Sd
  218. );
  219. LocalFree(pSD);
  220. if(!NT_SUCCESS(Status))
  221. ELF_LOG1(ERROR,
  222. "ChangeStringSD: RtlCopySecurityDescriptor %#x\n", Status);
  223. return Status;
  224. }
  225. NTSTATUS
  226. ElfpCreateLogFileObject(
  227. PLOGFILE LogFile,
  228. DWORD Type,
  229. HANDLE hLogRegKey,
  230. BOOL bFirstTime,
  231. BOOL * pbSDChanged
  232. )
  233. /*++
  234. Routine Description:
  235. This function creates the security descriptor which represents
  236. an active log file.
  237. Arguments:
  238. LogFile - pointer the the LOGFILE structure for this logfile
  239. Return Value:
  240. --*/
  241. {
  242. NTSTATUS Status;
  243. BOOL bRet;
  244. BOOL bCustomSDAlreadExists = FALSE;
  245. long lRet;
  246. PSECURITY_DESCRIPTOR pSD;
  247. LPWSTR pwsCustomSDDL = NULL;
  248. *pbSDChanged = TRUE; // SET TO FALSE iff current sd is unchanged
  249. // read the custom SDDL descriptor
  250. pwsCustomSDDL = GetCustomSDString(hLogRegKey, &bCustomSDAlreadExists);
  251. if(!bFirstTime)
  252. {
  253. // in the case of rescanning the registry, the value probably has not changed and in
  254. // that case we should return.
  255. if(pwsCustomSDDL == NULL && LogFile->pwsCurrCustomSD == NULL)
  256. {
  257. *pbSDChanged = FALSE;
  258. return STATUS_SUCCESS;
  259. }
  260. if(pwsCustomSDDL && LogFile->pwsCurrCustomSD &&
  261. _wcsicmp(pwsCustomSDDL, LogFile->pwsCurrCustomSD) == 0)
  262. {
  263. ElfpFreeBuffer(pwsCustomSDDL);
  264. *pbSDChanged = FALSE;
  265. return STATUS_SUCCESS;
  266. }
  267. }
  268. if(pwsCustomSDDL)
  269. {
  270. Status = ChangeStringSD(LogFile, pwsCustomSDDL);
  271. if(NT_SUCCESS(Status))
  272. {
  273. LogFile->pwsCurrCustomSD = pwsCustomSDDL; // take ownership
  274. return Status;
  275. }
  276. ElfpFreeBuffer(pwsCustomSDDL);
  277. ELF_LOG1(ERROR,
  278. "ElfpCreateLogFileObject: Failed trying to convert SDDL from registry %#x\n", Status);
  279. // we failed trying to create a custom SD. Warn the user and revert to using
  280. // the equivalent of the system log.
  281. Type = ELF_LOGFILE_SYSTEM;
  282. ElfpCreateElfEvent(EVENT_LOG_BAD_CUSTOM_SD,
  283. EVENTLOG_ERROR_TYPE,
  284. 0, // EventCategory
  285. 1, // NumberOfStrings
  286. &LogFile->LogModuleName->Buffer,
  287. NULL, // Data
  288. 0, // Datalength
  289. ELF_FORCE_OVERWRITE, // Overwrite if necc.
  290. FALSE); // for security file
  291. }
  292. // we failed because either there wasnt a string sd, or because there was
  293. // one and it was invalid (bNewCustomSD = FALSE)
  294. pwsCustomSDDL = GetDefaultSDDL(Type, hLogRegKey);
  295. if(pwsCustomSDDL == NULL)
  296. return STATUS_NO_MEMORY;
  297. Status = ChangeStringSD(LogFile, pwsCustomSDDL);
  298. if(NT_SUCCESS(Status))
  299. {
  300. LogFile->pwsCurrCustomSD = pwsCustomSDDL; // take ownership
  301. if(bCustomSDAlreadExists == FALSE && hLogRegKey)
  302. {
  303. lRet = RegSetValueExW(
  304. hLogRegKey,
  305. VALUE_CUSTOM_SD,
  306. 0,
  307. REG_SZ,
  308. (BYTE *)pwsCustomSDDL,
  309. 2*(wcslen(pwsCustomSDDL) + 1));
  310. if(lRet != ERROR_SUCCESS )
  311. ELF_LOG1(ERROR,
  312. "WriteDefaultSDDL: RegSetValueExW failed %#x\n", lRet);
  313. }
  314. }
  315. else
  316. {
  317. ELF_LOG1(ERROR,
  318. "ElfpCreateLogFileObject: failed trying to convert default SDDL %#x\n", Status);
  319. ElfpFreeBuffer(pwsCustomSDDL);
  320. }
  321. return Status;
  322. }
  323. NTSTATUS
  324. ElfpVerifyThatCallerIsLSASS(HANDLE ClientToken
  325. )
  326. /*++
  327. Routine Description:
  328. This is called if the someone is trying to register themselves as an
  329. event source for the security log. Only local copy of lsass.exe is
  330. allowed to do that.
  331. Return Value:
  332. NT status mapped to Win32 errors.
  333. --*/
  334. {
  335. UINT LocalFlag;
  336. long lCnt;
  337. ULONG pid;
  338. HANDLE hProcess;
  339. DWORD dwNumChar;
  340. WCHAR wModulePath[MAX_PATH + 1];
  341. WCHAR wLsassPath[MAX_PATH + 1];
  342. RPC_STATUS RpcStatus;
  343. BOOL Result;
  344. BYTE Buffer[SECURITY_MAX_SID_SIZE + sizeof(TOKEN_USER)];
  345. DWORD dwRequired;
  346. TOKEN_USER * pTokenUser = (TOKEN_USER *)Buffer;
  347. // first of all, only local calls are valid
  348. RpcStatus = I_RpcBindingIsClientLocal(
  349. 0, // Active RPC call we are servicing
  350. &LocalFlag
  351. );
  352. if( RpcStatus != RPC_S_OK )
  353. {
  354. ELF_LOG1(ERROR,
  355. "ElfpVerifyThatCallerIsLSASS: I_RpcBindingIsClientLocal failed %d\n",
  356. RpcStatus);
  357. return I_RpcMapWin32Status(RpcStatus);
  358. }
  359. if(LocalFlag == 0)
  360. {
  361. ELF_LOG1(ERROR,
  362. "ElfpVerifyThatCallerIsLSASS: Non local connect tried to get write access to security %d\n", 5);
  363. return STATUS_ACCESS_DENIED; // access denied
  364. }
  365. // Get the process id
  366. RpcStatus = I_RpcBindingInqLocalClientPID(NULL, &pid );
  367. if( RpcStatus != RPC_S_OK )
  368. {
  369. ELF_LOG1(ERROR,
  370. "ElfpVerifyThatCallerIsLSASS: I_RpcBindingInqLocalClientPID failed %d\n",
  371. RpcStatus);
  372. return I_RpcMapWin32Status(RpcStatus);
  373. }
  374. // Get the process
  375. hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid);
  376. if(hProcess == NULL)
  377. return STATUS_ACCESS_DENIED;
  378. // Get the module name of whoever is calling us.
  379. dwNumChar = GetModuleFileNameExW(hProcess, NULL, wModulePath, MAX_PATH);
  380. CloseHandle(hProcess);
  381. if(dwNumChar == 0)
  382. return STATUS_ACCESS_DENIED;
  383. dwNumChar = GetWindowsDirectoryW(wLsassPath, MAX_PATH);
  384. if(dwNumChar == 0)
  385. return GetLastError();
  386. if(dwNumChar > MAX_PATH - 19)
  387. return STATUS_ACCESS_DENIED; // should never happen
  388. StringCchCatW(wLsassPath, MAX_PATH + 1 , L"\\system32\\lsass.exe");
  389. if(lstrcmpiW(wLsassPath, wModulePath))
  390. {
  391. ELF_LOG1(ERROR,
  392. "ElfpVerifyThatCallerIsLSASS: Non lsass process connect tried to get write access to security, returning %d\n", 5);
  393. return STATUS_ACCESS_DENIED; // access denied
  394. }
  395. // make sure that the caller is running as local system account.
  396. Result = GetTokenInformation(ClientToken,
  397. TokenUser,
  398. Buffer,
  399. SECURITY_MAX_SID_SIZE + sizeof(TOKEN_USER),
  400. &dwRequired);
  401. if (!Result)
  402. {
  403. ELF_LOG1(ERROR,
  404. "ElfpVerifyThatCallerIsLSASS: could not get user sid, error=%d\n", GetLastError());
  405. return STATUS_ACCESS_DENIED; // access denied
  406. }
  407. Result = IsWellKnownSid(pTokenUser->User.Sid, WinLocalSystemSid);
  408. if (!Result)
  409. {
  410. ELF_LOG0(ERROR,
  411. "ElfpVerifyThatCallerIsLSASS: sid does not match local system\n");
  412. return STATUS_ACCESS_DENIED; // access denied
  413. }
  414. // One last check is to make sure that this access is granted only once
  415. lCnt = InterlockedIncrement(&g_lNumSecurityWriters);
  416. if(lCnt == 1)
  417. return 0; // all is well!
  418. else
  419. {
  420. InterlockedDecrement(&g_lNumSecurityWriters);
  421. ELF_LOG1(ERROR,
  422. "ElfpVerifyThatCallerIsLSASS: tried to get a second security write handle, returnin %d\n", 5);
  423. return STATUS_ACCESS_DENIED; // access denied
  424. }
  425. }
  426. void DumpClientProc()
  427. /*++
  428. Routine Description:
  429. This dumps the client's process id and is used for debugging purposes.
  430. --*/
  431. {
  432. ULONG pid;
  433. RPC_STATUS RpcStatus;
  434. // Get the process id
  435. RpcStatus = I_RpcBindingInqLocalClientPID(NULL, &pid );
  436. if( RpcStatus != RPC_S_OK )
  437. {
  438. ELF_LOG1(ERROR,
  439. "DumpClientProc: I_RpcBindingInqLocalClientPID failed %d\n",
  440. RpcStatus);
  441. return;
  442. }
  443. else
  444. ELF_LOG1(TRACE, "DumpClientProc: The client proc is %d\n", pid);
  445. return;
  446. }
  447. NTSTATUS
  448. ElfpAccessCheckAndAudit(
  449. IN LPWSTR SubsystemName,
  450. IN LPWSTR ObjectTypeName,
  451. IN LPWSTR ObjectName,
  452. IN OUT IELF_HANDLE ContextHandle,
  453. IN PSECURITY_DESCRIPTOR SecurityDescriptor,
  454. IN ACCESS_MASK DesiredAccess,
  455. IN PGENERIC_MAPPING GenericMapping,
  456. IN BOOL ForSecurityLog
  457. )
  458. /*++
  459. Routine Description:
  460. This function impersonates the caller so that it can perform access
  461. validation using NtAccessCheckAndAuditAlarm; and reverts back to
  462. itself before returning.
  463. Arguments:
  464. SubsystemName - Supplies a name string identifying the subsystem
  465. calling this routine.
  466. ObjectTypeName - Supplies the name of the type of the object being
  467. accessed.
  468. ObjectName - Supplies the name of the object being accessed.
  469. ContextHandle - Supplies the context handle to the object. On return, the
  470. granted access is written to the AccessGranted field of this structure
  471. if this call succeeds.
  472. SecurityDescriptor - A pointer to the Security Descriptor against which
  473. acccess is to be checked.
  474. DesiredAccess - Supplies desired acccess mask. This mask must have been
  475. previously mapped to contain no generic accesses.
  476. GenericMapping - Supplies a pointer to the generic mapping associated
  477. with this object type.
  478. ForSecurityLog - TRUE if the access check is for the security log.
  479. This is a special case that may require a privilege check.
  480. Return Value:
  481. NT status mapped to Win32 errors.
  482. --*/
  483. {
  484. NTSTATUS Status;
  485. RPC_STATUS RpcStatus;
  486. UNICODE_STRING Subsystem;
  487. UNICODE_STRING ObjectType;
  488. UNICODE_STRING Object;
  489. DWORD OrigDesiredAccess;
  490. BOOLEAN GenerateOnClose = FALSE;
  491. NTSTATUS AccessStatus;
  492. ACCESS_MASK GrantedAccess = 0;
  493. HANDLE ClientToken = NULL;
  494. PRIVILEGE_SET PrivilegeSet;
  495. ULONG PrivilegeSetLength = sizeof(PRIVILEGE_SET);
  496. ULONG privileges[1];
  497. OrigDesiredAccess = DesiredAccess;
  498. GenericMapping = &LogFileObjectMapping;
  499. RtlInitUnicodeString(&Subsystem, SubsystemName);
  500. RtlInitUnicodeString(&ObjectType, ObjectTypeName);
  501. RtlInitUnicodeString(&Object, ObjectName);
  502. RpcStatus = RpcImpersonateClient(NULL);
  503. if (RpcStatus != RPC_S_OK)
  504. {
  505. ELF_LOG1(ERROR,
  506. "ElfpAccessCheckAndAudit: RpcImpersonateClient failed %d\n",
  507. RpcStatus);
  508. return I_RpcMapWin32Status(RpcStatus);
  509. }
  510. //
  511. // Get a token handle for the client
  512. //
  513. Status = NtOpenThreadToken(NtCurrentThread(),
  514. TOKEN_QUERY, // DesiredAccess
  515. TRUE, // OpenAsSelf
  516. &ClientToken);
  517. if (!NT_SUCCESS(Status))
  518. {
  519. ELF_LOG1(ERROR,
  520. "ElfpAccessCheckAndAudit: NtOpenThreadToken failed %#x\n",
  521. Status);
  522. goto CleanExit;
  523. }
  524. // if the client is asking to write to the security log, make sure it is lsass.exe and no one
  525. // else.
  526. if(ForSecurityLog && (DesiredAccess & ELF_LOGFILE_WRITE))
  527. {
  528. Status = ElfpVerifyThatCallerIsLSASS(ClientToken);
  529. if (!NT_SUCCESS(Status))
  530. {
  531. ELF_LOG1(ERROR,
  532. "ElfpVerifyThatCallerIsLSASS failed %#x\n",
  533. Status);
  534. goto CleanExit;
  535. }
  536. gElfSecurityHandle = ContextHandle;
  537. ContextHandle->GrantedAccess = ELF_LOGFILE_ALL_ACCESS;
  538. Status = STATUS_SUCCESS;
  539. goto CleanExit;
  540. }
  541. else if(g_bGetClientProc)
  542. DumpClientProc();
  543. //
  544. // We want to see if we can get the desired access, and if we do
  545. // then we also want all our other accesses granted.
  546. // MAXIMUM_ALLOWED gives us this.
  547. //
  548. DesiredAccess |= MAXIMUM_ALLOWED;
  549. Status = NtAccessCheck(SecurityDescriptor,
  550. ClientToken,
  551. DesiredAccess,
  552. GenericMapping,
  553. &PrivilegeSet,
  554. &PrivilegeSetLength,
  555. &GrantedAccess,
  556. &AccessStatus);
  557. if (!NT_SUCCESS(Status))
  558. {
  559. ELF_LOG1(ERROR,
  560. "ElfpAccessCheckAndAudit: NtAccessCheck failed %#x\n",
  561. Status);
  562. goto CleanExit;
  563. }
  564. if (AccessStatus != STATUS_SUCCESS)
  565. {
  566. ELF_LOG1(TRACE,
  567. "ElfpAccessCheckAndAudit: NtAccessCheck refused access -- status is %#x\n",
  568. AccessStatus);
  569. //
  570. // If the access check failed, then some access can be granted based
  571. // on privileges.
  572. //
  573. if ((AccessStatus == STATUS_ACCESS_DENIED ||
  574. AccessStatus == STATUS_PRIVILEGE_NOT_HELD)
  575. )
  576. {
  577. //
  578. // MarkBl 1/30/95 : First, evalutate the existing code (performed
  579. // for read or clear access), since its
  580. // privilege check is more rigorous than mine.
  581. //
  582. Status = STATUS_ACCESS_DENIED;
  583. if (!(DesiredAccess & ELF_LOGFILE_WRITE) && ForSecurityLog)
  584. {
  585. //
  586. // If read or clear access to the security log is desired,
  587. // then we will see if this user passes the privilege check.
  588. //
  589. //
  590. // Do Privilege Check for SeSecurityPrivilege
  591. // (SE_SECURITY_NAME).
  592. //
  593. Status = ElfpTestClientPrivilege(SE_SECURITY_PRIVILEGE,
  594. ClientToken);
  595. if (NT_SUCCESS(Status))
  596. {
  597. GrantedAccess |= (ELF_LOGFILE_READ | ELF_LOGFILE_CLEAR);
  598. ELF_LOG0(TRACE,
  599. "ElfpAccessCheckAndAudit: ElfpTestClientPrivilege for "
  600. "SE_SECURITY_PRIVILEGE succeeded\n");
  601. }
  602. else
  603. {
  604. ELF_LOG1(TRACE,
  605. "ElfpAccessCheckAndAudit: ElfpTestClientPrivilege for "
  606. "SE_SECURITY_PRIVILEGE failed %#x\n",
  607. Status);
  608. }
  609. }
  610. //
  611. // If the backup privilege is held and access still has not been granted, give
  612. // them a very limited form of access.
  613. //
  614. if (!NT_SUCCESS(Status))
  615. {
  616. Status = ElfpTestClientPrivilege(SE_BACKUP_PRIVILEGE,
  617. ClientToken);
  618. if (NT_SUCCESS(Status))
  619. {
  620. ELF_LOG0(TRACE,
  621. "ElfpAccessCheckAndAudit: ElfpTestClientPrivilege for "
  622. "SE_BACKUP_PRIVILEGE succeeded\n");
  623. GrantedAccess |= ELF_LOGFILE_BACKUP;
  624. }
  625. else
  626. {
  627. ELF_LOG1(ERROR,
  628. "ElfpAccessCheckAndAudit: ElfpTestClientPrivilege for "
  629. "SE_BACKUP_PRIVILEGE failed %#x\n",
  630. Status);
  631. // special "fix" for wmi eventlog provider which is hard coded
  632. // to look for a specific error code
  633. if(AccessStatus == STATUS_PRIVILEGE_NOT_HELD)
  634. Status = AccessStatus;
  635. goto CleanExit;
  636. }
  637. }
  638. // special "fix" for wmi eventlog provider which is hard coded
  639. // to look for a specific error code
  640. if(!NT_SUCCESS(Status) && ForSecurityLog)
  641. Status = STATUS_PRIVILEGE_NOT_HELD;
  642. }
  643. else
  644. {
  645. Status = AccessStatus;
  646. }
  647. }
  648. //
  649. // Revert to Self
  650. //
  651. RpcStatus = RpcRevertToSelf();
  652. if (RpcStatus != RPC_S_OK)
  653. {
  654. ELF_LOG1(ERROR,
  655. "ElfpAccessCheckAndAudit: RpcRevertToSelf failed %d\n",
  656. RpcStatus);
  657. //
  658. // We don't return the error status here because we don't want
  659. // to write over the other status that is being returned.
  660. //
  661. }
  662. //
  663. // Get SeAuditPrivilege so I can call NtOpenObjectAuditAlarm.
  664. // If any of this stuff fails, I don't want the status to overwrite the
  665. // status that I got back from the access and privilege checks.
  666. //
  667. privileges[0] = SE_AUDIT_PRIVILEGE;
  668. AccessStatus = ElfpGetPrivilege(1, privileges);
  669. if (!NT_SUCCESS(AccessStatus))
  670. {
  671. ELF_LOG1(ERROR,
  672. "ElfpAccessCheckAndAudit: ElfpGetPrivilege (SE_AUDIT_PRIVILEGE) failed %#x\n",
  673. AccessStatus);
  674. }
  675. //
  676. // Call the Audit Alarm function.
  677. //
  678. AccessStatus = NtOpenObjectAuditAlarm(
  679. &Subsystem,
  680. (PVOID) &ContextHandle,
  681. &ObjectType,
  682. &Object,
  683. SecurityDescriptor,
  684. ClientToken, // Handle ClientToken
  685. DesiredAccess,
  686. GrantedAccess,
  687. &PrivilegeSet, // PPRIVLEGE_SET
  688. FALSE, // BOOLEAN ObjectCreation,
  689. TRUE, // BOOLEAN AccessGranted,
  690. &GenerateOnClose);
  691. if (!NT_SUCCESS(AccessStatus))
  692. {
  693. ELF_LOG1(ERROR,
  694. "ElfpAccessCheckAndAudit: NtOpenObjectAuditAlarm failed %#x\n",
  695. AccessStatus);
  696. }
  697. else
  698. {
  699. if (GenerateOnClose)
  700. {
  701. ContextHandle->Flags |= ELF_LOG_HANDLE_GENERATE_ON_CLOSE;
  702. }
  703. }
  704. //
  705. // Update the GrantedAccess in the context handle.
  706. //
  707. ContextHandle->GrantedAccess = GrantedAccess;
  708. if(ForSecurityLog)
  709. ContextHandle->GrantedAccess &= (~ELF_LOGFILE_WRITE);
  710. NtClose(ClientToken);
  711. ElfpReleasePrivilege();
  712. return Status;
  713. CleanExit:
  714. //
  715. // Revert to Self
  716. //
  717. RpcStatus = RpcRevertToSelf();
  718. if (RpcStatus != RPC_S_OK)
  719. {
  720. ELF_LOG1(ERROR,
  721. "ElfpAccessCheckAndAudit: RpcRevertToSelf (CleanExit) failed %d\n",
  722. RpcStatus);
  723. //
  724. // We don't return the error status here because we don't want
  725. // to write over the other status that is being returned.
  726. //
  727. }
  728. if (ClientToken != NULL)
  729. {
  730. NtClose(ClientToken);
  731. }
  732. return Status;
  733. }
  734. VOID
  735. ElfpCloseAudit(
  736. IN LPWSTR SubsystemName,
  737. IN IELF_HANDLE ContextHandle
  738. )
  739. /*++
  740. Routine Description:
  741. If the GenerateOnClose flag in the ContextHandle is set, then this function
  742. calls NtCloseAuditAlarm in order to generate a close audit for this handle.
  743. Arguments:
  744. ContextHandle - This is a pointer to an ELF_HANDLE structure. This is the
  745. handle that is being closed.
  746. Return Value:
  747. none.
  748. --*/
  749. {
  750. UNICODE_STRING Subsystem;
  751. NTSTATUS Status;
  752. NTSTATUS AccessStatus;
  753. ULONG privileges[1];
  754. RtlInitUnicodeString(&Subsystem, SubsystemName);
  755. if (ContextHandle->Flags & ELF_LOG_HANDLE_GENERATE_ON_CLOSE)
  756. {
  757. BOOLEAN WasEnabled = FALSE;
  758. //
  759. // Get Audit Privilege
  760. //
  761. privileges[0] = SE_AUDIT_PRIVILEGE;
  762. AccessStatus = ElfpGetPrivilege(1, privileges);
  763. if (!NT_SUCCESS(AccessStatus))
  764. {
  765. ELF_LOG1(ERROR,
  766. "ElfpCloseAudit: ElfpGetPrivilege (SE_AUDIT_PRIVILEGE) failed %#x\n",
  767. AccessStatus);
  768. }
  769. //
  770. // Generate the Audit.
  771. //
  772. Status = NtCloseObjectAuditAlarm(&Subsystem,
  773. ContextHandle,
  774. TRUE);
  775. if (!NT_SUCCESS(Status))
  776. {
  777. ELF_LOG1(ERROR,
  778. "ElfpCloseAudit: NtCloseObjectAuditAlarm failed %#x\n",
  779. Status);
  780. }
  781. ContextHandle->Flags &= (~ELF_LOG_HANDLE_GENERATE_ON_CLOSE);
  782. ElfpReleasePrivilege();
  783. }
  784. return;
  785. }
  786. NTSTATUS
  787. ElfpGetPrivilege(
  788. IN DWORD numPrivileges,
  789. IN PULONG pulPrivileges
  790. )
  791. /*++
  792. Routine Description:
  793. This function alters the privilege level for the current thread.
  794. It does this by duplicating the token for the current thread, and then
  795. applying the new privileges to that new token, then the current thread
  796. impersonates with that new token.
  797. Privileges can be relinquished by calling ElfpReleasePrivilege().
  798. Arguments:
  799. numPrivileges - This is a count of the number of privileges in the
  800. array of privileges.
  801. pulPrivileges - This is a pointer to the array of privileges that are
  802. desired. This is an array of ULONGs.
  803. Return Value:
  804. NO_ERROR - If the operation was completely successful.
  805. Otherwise, it returns mapped return codes from the various NT
  806. functions that are called.
  807. --*/
  808. {
  809. NTSTATUS ntStatus;
  810. HANDLE ourToken;
  811. HANDLE newToken;
  812. OBJECT_ATTRIBUTES Obja;
  813. SECURITY_QUALITY_OF_SERVICE SecurityQofS;
  814. ULONG returnLen;
  815. PTOKEN_PRIVILEGES pTokenPrivilege = NULL;
  816. DWORD i;
  817. //
  818. // Initialize the Privileges Structure
  819. //
  820. pTokenPrivilege =
  821. (PTOKEN_PRIVILEGES) ElfpAllocateBuffer(sizeof(TOKEN_PRIVILEGES)
  822. + (sizeof(LUID_AND_ATTRIBUTES) *
  823. numPrivileges));
  824. if (pTokenPrivilege == NULL)
  825. {
  826. ELF_LOG0(ERROR,
  827. "ElfpGetPrivilege: Unable to allocate memory for pTokenPrivilege\n");
  828. return STATUS_NO_MEMORY;
  829. }
  830. pTokenPrivilege->PrivilegeCount = numPrivileges;
  831. for (i = 0; i < numPrivileges; i++)
  832. {
  833. pTokenPrivilege->Privileges[i].Luid = RtlConvertLongToLuid(pulPrivileges[i]);
  834. pTokenPrivilege->Privileges[i].Attributes = SE_PRIVILEGE_ENABLED;
  835. }
  836. //
  837. // Initialize Object Attribute Structure.
  838. //
  839. InitializeObjectAttributes(&Obja, NULL, 0L, NULL, NULL);
  840. //
  841. // Initialize Security Quality Of Service Structure
  842. //
  843. SecurityQofS.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
  844. SecurityQofS.ImpersonationLevel = SecurityImpersonation;
  845. SecurityQofS.ContextTrackingMode = FALSE; // Snapshot client context
  846. SecurityQofS.EffectiveOnly = FALSE;
  847. Obja.SecurityQualityOfService = &SecurityQofS;
  848. //
  849. // Open our own Token
  850. //
  851. ntStatus = NtOpenProcessToken(NtCurrentProcess(),
  852. TOKEN_DUPLICATE,
  853. &ourToken);
  854. if (!NT_SUCCESS(ntStatus))
  855. {
  856. ELF_LOG1(ERROR,
  857. "ElfpGetPrivilege: NtOpenProcessToken failed %#x\n",
  858. ntStatus);
  859. ElfpFreeBuffer(pTokenPrivilege);
  860. return ntStatus;
  861. }
  862. //
  863. // Duplicate that Token
  864. //
  865. ntStatus = NtDuplicateToken(
  866. ourToken,
  867. TOKEN_IMPERSONATE | TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
  868. &Obja,
  869. FALSE, // Duplicate the entire token
  870. TokenImpersonation, // TokenType
  871. &newToken); // Duplicate token
  872. if (!NT_SUCCESS(ntStatus))
  873. {
  874. ELF_LOG1(ERROR,
  875. "ElfpGetPrivilege: NtDuplicateToken failed %#x\n",
  876. ntStatus);
  877. ElfpFreeBuffer(pTokenPrivilege);
  878. NtClose(ourToken);
  879. return ntStatus;
  880. }
  881. //
  882. // Add new privileges
  883. //
  884. ntStatus = NtAdjustPrivilegesToken(
  885. newToken, // TokenHandle
  886. FALSE, // DisableAllPrivileges
  887. pTokenPrivilege, // NewState
  888. 0, // size of previous state buffer
  889. NULL, // no previous state info
  890. &returnLen); // numBytes required for buffer.
  891. if (!NT_SUCCESS(ntStatus))
  892. {
  893. ELF_LOG1(ERROR,
  894. "ElfpGetPrivilege: NtAdjustPrivilegesToken failed %#x\n",
  895. ntStatus);
  896. ElfpFreeBuffer(pTokenPrivilege);
  897. NtClose(ourToken);
  898. NtClose(newToken);
  899. return ntStatus;
  900. }
  901. //
  902. // Begin impersonating with the new token
  903. //
  904. ntStatus = NtSetInformationThread(NtCurrentThread(),
  905. ThreadImpersonationToken,
  906. (PVOID) &newToken,
  907. (ULONG) sizeof(HANDLE));
  908. if (!NT_SUCCESS(ntStatus))
  909. {
  910. ELF_LOG1(ERROR,
  911. "ElfpGetPrivilege: NtAdjustPrivilegeToken failed %#x\n",
  912. ntStatus);
  913. ElfpFreeBuffer(pTokenPrivilege);
  914. NtClose(ourToken);
  915. NtClose(newToken);
  916. return ntStatus;
  917. }
  918. ElfpFreeBuffer(pTokenPrivilege);
  919. NtClose(ourToken);
  920. NtClose(newToken);
  921. return STATUS_SUCCESS;
  922. }
  923. NTSTATUS
  924. ElfpReleasePrivilege(
  925. VOID
  926. )
  927. /*++
  928. Routine Description:
  929. This function relinquishes privileges obtained by calling ElfpGetPrivilege().
  930. Arguments:
  931. none
  932. Return Value:
  933. STATUS_SUCCESS - If the operation was completely successful.
  934. Otherwise, it returns the error that occurred.
  935. --*/
  936. {
  937. NTSTATUS ntStatus;
  938. HANDLE NewToken;
  939. //
  940. // Revert To Self.
  941. //
  942. NewToken = NULL;
  943. ntStatus = NtSetInformationThread(NtCurrentThread(),
  944. ThreadImpersonationToken,
  945. &NewToken,
  946. (ULONG) sizeof(HANDLE));
  947. if (!NT_SUCCESS(ntStatus))
  948. {
  949. ELF_LOG1(ERROR,
  950. "ElfpReleasePrivilege: NtSetInformation thread failed %#x\n",
  951. ntStatus);
  952. return ntStatus;
  953. }
  954. return STATUS_SUCCESS;
  955. }
  956. NTSTATUS
  957. ElfpTestClientPrivilege(
  958. IN ULONG ulPrivilege,
  959. IN HANDLE hThreadToken OPTIONAL
  960. )
  961. /*++
  962. Routine Description:
  963. Checks if the client has the supplied privilege.
  964. Arguments:
  965. None
  966. Return Value:
  967. STATUS_SUCCESS - if the client has the appropriate privilege.
  968. STATUS_ACCESS_DENIED - client does not have the required privilege
  969. --*/
  970. {
  971. NTSTATUS Status;
  972. PRIVILEGE_SET PrivilegeSet;
  973. BOOLEAN Privileged;
  974. HANDLE Token;
  975. RPC_STATUS RpcStatus;
  976. UNICODE_STRING SubSystemName;
  977. RtlInitUnicodeString(&SubSystemName, L"Eventlog");
  978. if (hThreadToken != NULL)
  979. {
  980. Token = hThreadToken;
  981. }
  982. else
  983. {
  984. RpcStatus = RpcImpersonateClient(NULL);
  985. if (RpcStatus != RPC_S_OK)
  986. {
  987. ELF_LOG1(ERROR,
  988. "ElfpTestClientPrivilege: RpcImpersonateClient failed %d\n",
  989. RpcStatus);
  990. return I_RpcMapWin32Status(RpcStatus);
  991. }
  992. Status = NtOpenThreadToken(NtCurrentThread(),
  993. TOKEN_QUERY,
  994. TRUE,
  995. &Token);
  996. if (!NT_SUCCESS(Status))
  997. {
  998. //
  999. // Forget it.
  1000. //
  1001. ELF_LOG1(ERROR,
  1002. "ElfpTestClientPrivilege: NtOpenThreadToken failed %#x\n",
  1003. Status);
  1004. RpcRevertToSelf();
  1005. return Status;
  1006. }
  1007. }
  1008. //
  1009. // See if the client has the required privilege
  1010. //
  1011. PrivilegeSet.PrivilegeCount = 1;
  1012. PrivilegeSet.Control = PRIVILEGE_SET_ALL_NECESSARY;
  1013. PrivilegeSet.Privilege[0].Luid = RtlConvertLongToLuid(ulPrivilege);
  1014. PrivilegeSet.Privilege[0].Attributes = SE_PRIVILEGE_ENABLED;
  1015. Status = NtPrivilegeCheck(Token,
  1016. &PrivilegeSet,
  1017. &Privileged);
  1018. if (NT_SUCCESS(Status) || (Status == STATUS_PRIVILEGE_NOT_HELD))
  1019. {
  1020. Status = NtPrivilegeObjectAuditAlarm(
  1021. &SubSystemName,
  1022. NULL,
  1023. Token,
  1024. 0,
  1025. &PrivilegeSet,
  1026. Privileged);
  1027. if (!NT_SUCCESS(Status))
  1028. {
  1029. ELF_LOG1(ERROR,
  1030. "ElfpTestClientPrivilege: NtPrivilegeObjectAuditAlarm failed %#x\n",
  1031. Status);
  1032. }
  1033. }
  1034. else
  1035. {
  1036. ELF_LOG1(ERROR,
  1037. "ElfpTestClientPrivilege: NtPrivilegeCheck failed %#x\n",
  1038. Status);
  1039. }
  1040. if (hThreadToken == NULL )
  1041. {
  1042. //
  1043. // We impersonated inside of this function
  1044. //
  1045. NtClose(Token);
  1046. RpcRevertToSelf();
  1047. }
  1048. //
  1049. // Handle unexpected errors
  1050. //
  1051. if (!NT_SUCCESS(Status))
  1052. {
  1053. ELF_LOG1(ERROR,
  1054. "ElfpTestClientPrivilege: Failed %#x\n",
  1055. Status);
  1056. return Status;
  1057. }
  1058. //
  1059. // If they failed the privilege check, return an error
  1060. //
  1061. if (!Privileged)
  1062. {
  1063. ELF_LOG0(ERROR,
  1064. "ElfpTestClientPrivilege: Client failed privilege check\n");
  1065. return STATUS_ACCESS_DENIED;
  1066. }
  1067. //
  1068. // They passed muster
  1069. //
  1070. return STATUS_SUCCESS;
  1071. }