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.

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