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.

710 lines
18 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1996.
  5. //
  6. // File: sadat.cxx
  7. //
  8. // Contents: Routines which manipulate the SA.DAT file in the Tasks
  9. // folder. This file is used by both the service and the UI
  10. // to determine service state, OS info, etc.
  11. //
  12. // Classes: None.
  13. //
  14. // Functions: SADatGetData
  15. // SADatPath
  16. // SADatCreate
  17. // SADatSetData
  18. // SADatSetSecurity
  19. //
  20. // History: 08-Jul-96 MarkBl Created
  21. // 22-May-01 drbeck, jbenton Added SADatSetSecurity
  22. //
  23. //----------------------------------------------------------------------------
  24. #include "..\pch\headers.hxx"
  25. #pragma hdrstop
  26. #include "..\inc\debug.hxx"
  27. #include "..\inc\sadat.hxx"
  28. //Required for adding ACE to sa.dat file
  29. #include <Accctrl.h>
  30. #include <Aclapi.h>
  31. DWORD
  32. SADatSetSecurity(
  33. HANDLE hFile); // handle to file to add ACE
  34. HRESULT
  35. SADatGetData(
  36. HANDLE hFile,
  37. DWORD cbData,
  38. BYTE rgbData[]);
  39. void
  40. SADatPath(
  41. LPCTSTR ptszFolderPath,
  42. LPTSTR ptszSADatPath);
  43. #ifdef _CHICAGO_
  44. //
  45. // These routines exist on Win98, NT4 and NT5 but not on Win95
  46. //
  47. typedef VOID (APIENTRY *PTIMERAPCROUTINE)(
  48. LPVOID lpArgToCompletionRoutine,
  49. DWORD dwTimerLowValue,
  50. DWORD dwTimerHighValue
  51. );
  52. typedef HANDLE (WINAPI *PFNCreateWaitableTimerA)(
  53. LPSECURITY_ATTRIBUTES lpTimerAttributes,
  54. BOOL bManualReset,
  55. LPCSTR lpTimerName
  56. );
  57. typedef BOOL (WINAPI *PFNSetWaitableTimer)(
  58. HANDLE hTimer,
  59. const LARGE_INTEGER *lpDueTime,
  60. LONG lPeriod,
  61. PTIMERAPCROUTINE pfnCompletionRoutine,
  62. LPVOID lpArgToCompletionRoutine,
  63. BOOL fResume
  64. );
  65. #endif // _CHICAGO_
  66. //+---------------------------------------------------------------------------
  67. //
  68. // Function: SADatGetData
  69. //
  70. // Synopsis: Retrieve and validate data from the file, SA.DAT, located
  71. // in the folder path specified.
  72. //
  73. // Arguments: [ptszFolderPath] -- SA.DAT path location.
  74. // [cbData] -- Data buffer size.
  75. // [rgbData] -- Data buffer.
  76. // [phFile] -- Optional return handle.
  77. //
  78. // Returns: S_OK
  79. // E_UNEXPECTED if the amount read isn't what we expected or the
  80. // data is invalid.
  81. // Create/ReadFile HRESULT status code on failure.
  82. //
  83. // Notes: None.
  84. //
  85. //----------------------------------------------------------------------------
  86. HRESULT
  87. SADatGetData(
  88. LPCTSTR ptszFolderPath,
  89. DWORD cbData,
  90. BYTE rgbData[],
  91. HANDLE * phFile)
  92. {
  93. schAssert(cbData >= SA_DAT_VERSION_ONE_SIZE);
  94. //
  95. // Open SA.DAT in the folder path indicated. Fail if it doesn't exist.
  96. //
  97. TCHAR tszSADatPath[MAX_PATH + 1];
  98. SADatPath(ptszFolderPath, tszSADatPath);
  99. HANDLE hFile = CreateFile(tszSADatPath,
  100. GENERIC_READ |
  101. (phFile != NULL ? GENERIC_WRITE : 0),
  102. FILE_SHARE_READ | FILE_SHARE_WRITE,
  103. NULL,
  104. OPEN_EXISTING,
  105. FILE_ATTRIBUTE_HIDDEN,
  106. NULL);
  107. if (hFile == INVALID_HANDLE_VALUE)
  108. {
  109. #if DBG == 1
  110. if (GetLastError() != ERROR_FILE_NOT_FOUND)
  111. {
  112. CHECK_HRESULT(HRESULT_FROM_WIN32(GetLastError()));
  113. }
  114. #endif // DBG == 1
  115. return HRESULT_FROM_WIN32(GetLastError());
  116. }
  117. //
  118. // Read & validate file content.
  119. //
  120. HRESULT hr = SADatGetData(hFile, cbData, rgbData);
  121. if (SUCCEEDED(hr))
  122. {
  123. //
  124. // No need to verify the size or the service flags. We've read at
  125. // least the amount expected, and for this version, only the LSB
  126. // of the service flags is used. Future versions may wish to do
  127. // further flag checks.
  128. //
  129. BYTE bPlatform;
  130. CopyMemory(&bPlatform, rgbData + SA_DAT_PLATFORM_OFFSET,
  131. sizeof(bPlatform));
  132. if (bPlatform != VER_PLATFORM_WIN32_NT &&
  133. bPlatform != VER_PLATFORM_WIN32_WINDOWS)
  134. {
  135. hr = E_UNEXPECTED;
  136. CHECK_HRESULT(hr);
  137. }
  138. else
  139. {
  140. if (phFile != NULL) // Optional return handle.
  141. {
  142. //
  143. // Reset the file pointer to the beginning for the returned
  144. // handle.
  145. //
  146. if (SetFilePointer(hFile,
  147. 0,
  148. NULL,
  149. FILE_BEGIN) != -1)
  150. {
  151. *phFile = hFile;
  152. hFile = NULL;
  153. }
  154. else
  155. {
  156. hr = HRESULT_FROM_WIN32(GetLastError());
  157. CHECK_HRESULT(hr);
  158. }
  159. }
  160. }
  161. }
  162. if (hFile != NULL) CloseHandle(hFile);
  163. return(hr);
  164. }
  165. //+---------------------------------------------------------------------------
  166. //
  167. // Function: SADatGetData
  168. //
  169. // Synopsis: A more refined version of the overloaded function above.
  170. // Return individual fields instead of raw data.
  171. //
  172. // Arguments: [ptszFolderPath] -- SA.DAT path location.
  173. // [pdwVersion] -- Returned version.
  174. // [pbPlatform] -- Returned platform id.
  175. // [prgSvcFlags] -- Returned service flags.
  176. //
  177. // Returns: SADatGetData return code.
  178. //
  179. // Notes: None.
  180. //
  181. //----------------------------------------------------------------------------
  182. HRESULT
  183. SADatGetData(
  184. LPCTSTR ptszFolderPath,
  185. DWORD * pdwVersion,
  186. BYTE * pbPlatform,
  187. BYTE * prgSvcFlags)
  188. {
  189. BYTE rgbData[SA_DAT_VERSION_ONE_SIZE];
  190. HRESULT hr;
  191. hr = SADatGetData(ptszFolderPath, SA_DAT_VERSION_ONE_SIZE, rgbData);
  192. if (SUCCEEDED(hr))
  193. {
  194. *pdwVersion = (DWORD)*rgbData;
  195. CopyMemory(pbPlatform, rgbData + SA_DAT_PLATFORM_OFFSET,
  196. sizeof(*pbPlatform));
  197. CopyMemory(prgSvcFlags, rgbData + SA_DAT_SVCFLAGS_OFFSET,
  198. sizeof(*prgSvcFlags));
  199. }
  200. return(hr);
  201. }
  202. //+---------------------------------------------------------------------------
  203. //
  204. // Function: SADatCreate
  205. //
  206. // Synopsis: Create & initialize the binary file, SA.DAT, in the Tasks
  207. // folder. The platform id is set to indicate which OS we're
  208. // currently running under; the service flag is set to 1
  209. // to indicate the service is running.
  210. //
  211. // Arguments: [ptszFolderPath] -- Path to the Tasks folder.
  212. // [fServiceRunning] -- Flag indicating running service.
  213. //
  214. // Returns: S_OK
  215. // E_UNEXPECTED if the amount written isn't what we expected.
  216. // Create/WriteFile HRESULT status code on failure.
  217. //
  218. // Notes: This is to be called by the service only with service start.
  219. //
  220. //----------------------------------------------------------------------------
  221. HRESULT
  222. SADatCreate(
  223. LPCTSTR ptszFolderPath,
  224. BOOL fServiceRunning)
  225. {
  226. BYTE rgbData[SA_DAT_VERSION_ONE_SIZE];
  227. DWORD dwResult;
  228. //
  229. // Set size.
  230. //
  231. DWORD dwSize = SA_DAT_VERSION_ONE_SIZE;
  232. CopyMemory(rgbData, &dwSize, sizeof(dwSize));
  233. //
  234. // Set the platform id.
  235. //
  236. OSVERSIONINFO osverinfo;
  237. osverinfo.dwOSVersionInfoSize = sizeof(osverinfo);
  238. if (!GetVersionEx(&osverinfo))
  239. {
  240. return HRESULT_FROM_WIN32(GetLastError());
  241. }
  242. BYTE bPlatform;
  243. if (osverinfo.dwPlatformId == VER_PLATFORM_WIN32_NT) // NT
  244. {
  245. bPlatform = VER_PLATFORM_WIN32_NT;
  246. }
  247. else // Assume windows
  248. {
  249. bPlatform = VER_PLATFORM_WIN32_WINDOWS;
  250. }
  251. CopyMemory(rgbData + SA_DAT_PLATFORM_OFFSET, &bPlatform,
  252. sizeof(bPlatform));
  253. //
  254. // Set the service flags to indicate the service is running.
  255. //
  256. BYTE rgfServiceFlags = (fServiceRunning ? SA_DAT_SVCFLAG_SVC_RUNNING : 0);
  257. //
  258. // Determine whether the machine supports wakeup timers.
  259. //
  260. if (ResumeTimersSupported())
  261. {
  262. rgfServiceFlags |= SA_DAT_SVCFLAG_RESUME_TIMERS;
  263. }
  264. rgbData[SA_DAT_SVCFLAGS_OFFSET] = rgfServiceFlags;
  265. //
  266. // Create the file. Overwrite, if it exists.
  267. //
  268. TCHAR tszSADatPath[MAX_PATH + 1];
  269. SADatPath(ptszFolderPath, tszSADatPath);
  270. //
  271. // First clear any extraneous attribute bits that were added by
  272. // somebody else that would cause the CreateFile to fail
  273. //
  274. if (!SetFileAttributes(tszSADatPath, FILE_ATTRIBUTE_HIDDEN))
  275. {
  276. #if DBG == 1
  277. //
  278. // Not a problem if the file doesn't exist
  279. //
  280. if (GetLastError() != ERROR_FILE_NOT_FOUND)
  281. {
  282. CHECK_HRESULT(HRESULT_FROM_WIN32(GetLastError()));
  283. }
  284. #endif // DBG == 1
  285. }
  286. HANDLE hFile = CreateFile(tszSADatPath,
  287. GENERIC_READ | GENERIC_WRITE | WRITE_DAC,
  288. FILE_SHARE_READ | FILE_SHARE_WRITE,
  289. NULL,
  290. CREATE_ALWAYS,
  291. FILE_ATTRIBUTE_HIDDEN,
  292. NULL);
  293. if (hFile == INVALID_HANDLE_VALUE)
  294. {
  295. CHECK_HRESULT(HRESULT_FROM_WIN32(GetLastError()));
  296. return HRESULT_FROM_WIN32(GetLastError());
  297. }
  298. // Add read ACE for authenticated users
  299. dwResult = SADatSetSecurity(hFile);
  300. if( ERROR_SUCCESS != dwResult )
  301. {
  302. CloseHandle(hFile);
  303. CHECK_HRESULT(HRESULT_FROM_WIN32(dwResult));
  304. return HRESULT_FROM_WIN32(dwResult);
  305. }
  306. //
  307. // Write out the contents.
  308. //
  309. HRESULT hr = SADatSetData(hFile, sizeof(rgbData), rgbData);
  310. CloseHandle(hFile);
  311. return hr;
  312. }
  313. //+---------------------------------------------------------------------------
  314. //
  315. // Function: SADatGetData
  316. //
  317. // Synopsis: Nothing SA.DAT-specific here. Just a helper to read a blob
  318. // of bytes from the file indicated, and ensure we read the
  319. // amount expected.
  320. //
  321. // Arguments: [hFile] -- Destination file.
  322. // [cbData] -- Amount of data to read.
  323. // [rgbData] -- Read data.
  324. //
  325. // Returns: S_OK
  326. // E_UNEXPECTED if the amount read isn't what we expected.
  327. // ReadFile HRESULT status code on failure.
  328. //
  329. // Notes: None.
  330. //
  331. //----------------------------------------------------------------------------
  332. HRESULT
  333. SADatGetData(
  334. HANDLE hFile,
  335. DWORD cbData,
  336. BYTE rgbData[])
  337. {
  338. DWORD cbRead;
  339. if (!ReadFile(hFile,
  340. rgbData,
  341. cbData,
  342. &cbRead,
  343. NULL))
  344. {
  345. CHECK_HRESULT(HRESULT_FROM_WIN32(GetLastError()));
  346. return HRESULT_FROM_WIN32(GetLastError());
  347. }
  348. if (cbRead != cbData)
  349. {
  350. CHECK_HRESULT(E_UNEXPECTED);
  351. return E_UNEXPECTED;
  352. }
  353. return S_OK;
  354. }
  355. //+---------------------------------------------------------------------------
  356. //
  357. // Function: SADatSetData
  358. //
  359. // Synopsis: Nothing SA.DAT-specific here. Just a helper to write a blob
  360. // of bytes to the file indicated, and ensure we wrote the
  361. // amount expected.
  362. //
  363. // Arguments: [hFile] -- Destination file.
  364. // [cbData] -- Amount of data to write.
  365. // [rgbData] -- Actual data.
  366. //
  367. // Returns: S_OK
  368. // E_UNEXPECTED if the amount written isn't what we expected.
  369. // WriteFile HRESULT status code on failure.
  370. //
  371. // Notes: None.
  372. //
  373. //----------------------------------------------------------------------------
  374. HRESULT
  375. SADatSetData(
  376. HANDLE hFile,
  377. DWORD cbData,
  378. const BYTE rgbData[])
  379. {
  380. DWORD cbWritten;
  381. if (!WriteFile(hFile,
  382. rgbData,
  383. cbData,
  384. &cbWritten,
  385. NULL))
  386. {
  387. CHECK_HRESULT(HRESULT_FROM_WIN32(GetLastError()));
  388. return HRESULT_FROM_WIN32(GetLastError());
  389. }
  390. if (cbWritten != cbData)
  391. {
  392. CHECK_HRESULT(E_UNEXPECTED);
  393. return E_UNEXPECTED;
  394. }
  395. return S_OK;
  396. }
  397. //+---------------------------------------------------------------------------
  398. //
  399. // Function: SADatPath
  400. //
  401. // Synopsis: Return a concatenation the folder path and "\SA.DAT".
  402. //
  403. // Arguments: [ptszFolderPath] -- Folder path.
  404. // [ptszSADatPath] -- New path.
  405. //
  406. // Returns: None.
  407. //
  408. // Notes: None.
  409. //
  410. //----------------------------------------------------------------------------
  411. void
  412. SADatPath(
  413. LPCTSTR ptszFolderPath,
  414. LPTSTR ptszSADatPath)
  415. {
  416. TCHAR tszSADat[] = TEXT("\\SA.DAT");
  417. #if (DBG == 1)
  418. //
  419. // Assert that the folder path:
  420. // is not NULL
  421. // is not an empty string
  422. // does not end in a backslash
  423. //
  424. schAssert(ptszFolderPath != NULL);
  425. schAssert(*ptszFolderPath);
  426. LPCTSTR ptszLastSlash = _tcsrchr(ptszFolderPath, TEXT('\\'));
  427. schAssert(!ptszLastSlash || ptszLastSlash[1]);
  428. #endif // (DBG == 1)
  429. lstrcpy(ptszSADatPath, ptszFolderPath);
  430. lstrcat(ptszSADatPath, tszSADat);
  431. }
  432. //+---------------------------------------------------------------------------
  433. //
  434. // Function: ResumeTimersSupported
  435. //
  436. // Synopsis: Jumps through hoops to determine whether the machine supports
  437. // resume timers (aka wakeup timers)
  438. //
  439. // Arguments: None.
  440. //
  441. // Returns: TRUE - Resume timers are supported
  442. // FALSE - Resume timers are not supported
  443. //
  444. //----------------------------------------------------------------------------
  445. BOOL
  446. ResumeTimersSupported()
  447. {
  448. HANDLE hTimer;
  449. #ifdef _CHICAGO_
  450. PFNCreateWaitableTimerA pfnCreateWaitableTimerA;
  451. PFNSetWaitableTimer pfnSetWaitableTimer;
  452. HMODULE hKernel32Dll = GetModuleHandle("KERNEL32.DLL");
  453. if (hKernel32Dll == NULL)
  454. {
  455. ERR_OUT("Load of kernel32.dll", GetLastError());
  456. return FALSE;
  457. }
  458. pfnCreateWaitableTimerA = (PFNCreateWaitableTimerA)
  459. GetProcAddress(hKernel32Dll, "CreateWaitableTimerA");
  460. pfnSetWaitableTimer = (PFNSetWaitableTimer)
  461. GetProcAddress(hKernel32Dll, "SetWaitableTimer");
  462. if (pfnCreateWaitableTimerA == NULL ||
  463. pfnSetWaitableTimer == NULL)
  464. {
  465. ERR_OUT("GetProcAddress in kernel32.dll", GetLastError());
  466. return FALSE;
  467. }
  468. hTimer = pfnCreateWaitableTimerA(NULL, TRUE, NULL);
  469. #else // !_CHICAGO_
  470. hTimer = CreateWaitableTimer(NULL, TRUE, NULL);
  471. #endif // _CHICAGO_
  472. if (hTimer == NULL)
  473. {
  474. ERR_OUT("CreateWaitableTimer", GetLastError());
  475. return FALSE;
  476. }
  477. LARGE_INTEGER li = { 0xFFFFFFFF, 0xFFFFFFFF };
  478. BOOL fResult = FALSE;
  479. #ifdef _CHICAGO_
  480. if (pfnSetWaitableTimer(hTimer, &li, 0, NULL, 0, TRUE))
  481. #else // !_CHICAGO_
  482. if (SetWaitableTimer(hTimer, &li, 0, NULL, 0, TRUE))
  483. #endif // _CHICAGO_
  484. {
  485. //
  486. // By design, this call to SetWaitableTimer will succeed even on
  487. // machines that do NOT support resume timers. GetLastError must
  488. // be used to determine if, indeed, the machine supports resume
  489. // timers.
  490. //
  491. if (GetLastError() == ERROR_NOT_SUPPORTED)
  492. {
  493. // This machine does not support resume timers
  494. DBG_OUT("Machine does not support resume timers");
  495. }
  496. else
  497. {
  498. DBG_OUT("Machine supports resume timers");
  499. fResult = TRUE;
  500. }
  501. }
  502. else
  503. {
  504. ERR_OUT("SetWaitableTimer", GetLastError());
  505. }
  506. CloseHandle(hTimer);
  507. return fResult;
  508. }
  509. //+---------------------------------------------------------------------------
  510. //
  511. // Function: SADatSetSecurity
  512. //
  513. // Synopsis: Add an ACE to the file that allows authenticated users to
  514. // read the file. We cannot rely on inheriting the necessary
  515. // permissions of the containing folder.
  516. //
  517. // Arguments: [hFile] -- Destination file.
  518. //
  519. // Returns: ERROR_SUCCESS upon success
  520. // Non zero value upon failure
  521. //
  522. // Notes: None.
  523. //
  524. //----------------------------------------------------------------------------
  525. DWORD SADatSetSecurity (
  526. HANDLE hFile // handle to file
  527. )
  528. {
  529. DWORD dwRes = ERROR_SUCCESS;
  530. PSID pSid = NULL;
  531. PACL pOldDACL = NULL;
  532. PACL pNewDACL = NULL;
  533. PSECURITY_DESCRIPTOR pSD = NULL;
  534. EXPLICIT_ACCESS ExplicAcc;
  535. schAssert(hFile != NULL);
  536. // Create the SID for "NTAUTH\Athenticated Users"
  537. SID_IDENTIFIER_AUTHORITY NtAuth = SECURITY_NT_AUTHORITY;
  538. if ( !AllocateAndInitializeSid(
  539. &NtAuth,
  540. 1,
  541. SECURITY_AUTHENTICATED_USER_RID,
  542. 0, 0, 0, 0, 0, 0, 0,
  543. &pSid
  544. )
  545. )
  546. {
  547. dwRes = GetLastError();
  548. goto Cleanup;
  549. }
  550. // Get a pointer to the existing DACL.
  551. dwRes = GetSecurityInfo(
  552. hFile,
  553. SE_FILE_OBJECT,
  554. DACL_SECURITY_INFORMATION,
  555. NULL,
  556. NULL,
  557. &pOldDACL,
  558. NULL,
  559. &pSD
  560. );
  561. if (ERROR_SUCCESS != dwRes)
  562. {
  563. goto Cleanup;
  564. }
  565. // Initialize an EXPLICIT_ACCESS structure for the new ACE.
  566. ZeroMemory(&ExplicAcc, sizeof(EXPLICIT_ACCESS));
  567. ExplicAcc.grfAccessPermissions = GENERIC_READ;
  568. ExplicAcc.grfAccessMode = GRANT_ACCESS;
  569. ExplicAcc.grfInheritance = NO_INHERITANCE;
  570. ExplicAcc.Trustee.TrusteeForm = TRUSTEE_IS_SID;
  571. ExplicAcc.Trustee.ptstrName = (LPTSTR)pSid;
  572. // Create a new ACL that merges the new ACE
  573. // into the existing DACL.
  574. dwRes = SetEntriesInAcl(1, &ExplicAcc, pOldDACL, &pNewDACL);
  575. if (ERROR_SUCCESS != dwRes)
  576. {
  577. goto Cleanup;
  578. }
  579. // Attach the new ACL as the file's DACL.
  580. dwRes = SetSecurityInfo(
  581. hFile,
  582. SE_FILE_OBJECT,
  583. DACL_SECURITY_INFORMATION,
  584. NULL,
  585. NULL,
  586. pNewDACL,
  587. NULL
  588. );
  589. if (ERROR_SUCCESS != dwRes)
  590. {
  591. goto Cleanup;
  592. }
  593. Cleanup:
  594. if(pSD != NULL)
  595. {
  596. LocalFree((HLOCAL) pSD);
  597. }
  598. if(pNewDACL != NULL)
  599. {
  600. LocalFree((HLOCAL) pNewDACL);
  601. }
  602. if( pSid != NULL )
  603. {
  604. FreeSid(pSid);
  605. }
  606. return dwRes;
  607. }