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.

686 lines
18 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1996.
  5. //
  6. // File: secmisc.cxx
  7. //
  8. // Contents: Code to retrieve security-related information from the job
  9. // object. Function names partially describe the intended
  10. // function - we don't want to give too much away.
  11. //
  12. // Classes: None.
  13. //
  14. // Functions: CloseFile
  15. // GetFileInformation
  16. //
  17. // History: 15-May-96 MarkBl Created
  18. //
  19. //----------------------------------------------------------------------------
  20. #include "..\pch\headers.hxx"
  21. #pragma hdrstop
  22. #include <ntsecapi.h>
  23. #include <mstask.h>
  24. #include <msterr.h>
  25. #include "debug.hxx"
  26. #include "lsa.hxx"
  27. #include "globals.hxx"
  28. #include "misc.hxx"
  29. BOOL WaitForMUP (DWORD dwMaxWait);
  30. BOOL WaitForServiceToStart (LPTSTR lpServiceName, DWORD dwMaxWait);
  31. //
  32. // Defined in globals.cxx
  33. //
  34. extern CStaticCritSec gcsSSCritSection;
  35. //
  36. // Defined in security.cxx.
  37. //
  38. extern DWORD gdwKeyElement;
  39. extern POLICY_ACCOUNT_DOMAIN_INFO * gpDomainInfo;
  40. extern WCHAR gwszComputerName[MAX_COMPUTERNAME_LENGTH + 2];
  41. //+---------------------------------------------------------------------------
  42. //
  43. // Function: CloseFile
  44. //
  45. // Synopsis:
  46. //
  47. // Arguments: [hFile] --
  48. // [ccApplication] --
  49. // [wszApplication] --
  50. // [hrPrevious] --
  51. //
  52. // Returns: S_OK
  53. // SCHED_E_INVALID_TASK
  54. // E_UNEXPECTED
  55. // HRESULT argument, if it is an error.
  56. //
  57. // Notes: None.
  58. //
  59. //----------------------------------------------------------------------------
  60. HRESULT
  61. CloseFile(
  62. HANDLE hFile,
  63. WORD ccApplication,
  64. WCHAR wszApplication[],
  65. HRESULT hrPrevious)
  66. {
  67. HRESULT hr = S_OK;
  68. DWORD dwBytesRead;
  69. WCHAR * pwsz;
  70. WORD wAppOffset;
  71. WORD cch;
  72. //
  73. // If the previous operation failed, skip the application read.
  74. //
  75. if (FAILED(hrPrevious))
  76. {
  77. hr = hrPrevious;
  78. goto ErrorExit;
  79. }
  80. //
  81. // Read the offset to the application name.
  82. //
  83. if (!ReadFile(hFile, &wAppOffset, sizeof(wAppOffset), &dwBytesRead, NULL))
  84. {
  85. CHECK_HRESULT(HRESULT_FROM_WIN32(GetLastError()));
  86. hr = SCHED_E_INVALID_TASK;
  87. goto ErrorExit;
  88. }
  89. //
  90. // Move to read the application name.
  91. //
  92. if (SetFilePointer(hFile, wAppOffset, NULL, FILE_BEGIN) != -1)
  93. {
  94. //
  95. // Read the application size, allocate sufficient buffer space
  96. // and read the application string.
  97. //
  98. if (!ReadFile(hFile, &cch, sizeof(cch), &dwBytesRead, NULL) ||
  99. dwBytesRead != sizeof(cch))
  100. {
  101. CHECK_HRESULT(HRESULT_FROM_WIN32(GetLastError()));
  102. hr = SCHED_E_INVALID_TASK;
  103. goto ErrorExit;
  104. }
  105. if (!cch)
  106. {
  107. wszApplication[0] = L'\0';
  108. }
  109. else if (cch > ccApplication)
  110. {
  111. hr = E_UNEXPECTED;
  112. CHECK_HRESULT(hr);
  113. goto ErrorExit;
  114. }
  115. else
  116. {
  117. if (!ReadFile(hFile,
  118. wszApplication,
  119. cch * sizeof(WCHAR),
  120. &dwBytesRead,
  121. NULL))
  122. {
  123. CHECK_HRESULT(HRESULT_FROM_WIN32(GetLastError()));
  124. hr = SCHED_E_INVALID_TASK;
  125. goto ErrorExit;
  126. }
  127. if (dwBytesRead != (cch * sizeof(WCHAR)))
  128. {
  129. hr = SCHED_E_INVALID_TASK;
  130. CHECK_HRESULT(hr);
  131. goto ErrorExit;
  132. }
  133. if (wszApplication[cch - 1] != L'\0')
  134. {
  135. hr = SCHED_E_INVALID_TASK;
  136. CHECK_HRESULT(hr);
  137. goto ErrorExit;
  138. }
  139. }
  140. }
  141. else
  142. {
  143. CHECK_HRESULT(HRESULT_FROM_WIN32(GetLastError()));
  144. hr = SCHED_E_INVALID_TASK;
  145. }
  146. ErrorExit:
  147. if (hFile != NULL) CloseHandle(hFile);
  148. return(hr);
  149. }
  150. //+---------------------------------------------------------------------------
  151. //
  152. // Function: GetFileInformation
  153. //
  154. // Synopsis:
  155. //
  156. // Arguments: [pwszFileName] --
  157. // [hFile] --
  158. // [pcbOwnerSid] --
  159. // [ppOwnerSid] --
  160. // [ppOwnerSecDescr] --
  161. // [ccOwnerName] --
  162. // [ccOwnerDomain] --
  163. // [ccApplication] --
  164. // [wszOwnerName] --
  165. // [wszOwnerDomain] --
  166. // [wszApplication] --
  167. // [pftCreationTime] --
  168. // [pdwVolumeSerialNo] --
  169. //
  170. // Returns: HRESULT
  171. //
  172. // Notes: None.
  173. //
  174. //----------------------------------------------------------------------------
  175. HRESULT
  176. GetFileInformation(
  177. LPCWSTR pwszFileName,
  178. DWORD * pcbOwnerSid,
  179. PSID * ppOwnerSid,
  180. PSECURITY_DESCRIPTOR * ppOwnerSecDescr,
  181. UUID * pJobID,
  182. DWORD ccOwnerName,
  183. DWORD ccOwnerDomain,
  184. DWORD ccApplication,
  185. WCHAR wszOwnerName[],
  186. WCHAR wszOwnerDomain[],
  187. WCHAR wszApplication[],
  188. FILETIME * pftCreationTime,
  189. DWORD * pdwVolumeSerialNo)
  190. {
  191. BY_HANDLE_FILE_INFORMATION hinfo;
  192. HANDLE hFile;
  193. SECURITY_DESCRIPTOR * pOwnerSecDescr = NULL;
  194. PSID pOwnerSid = NULL;
  195. DWORD cbOwnerSid = 0;
  196. DWORD cbSizeNeeded;
  197. BOOL fRet, fOwnerDefaulted;
  198. static s_bWaitForWorkStation = TRUE;
  199. HRESULT hr = OpenFileWithRetry(pwszFileName, GENERIC_READ, FILE_SHARE_READ, &hFile);
  200. if (FAILED(hr))
  201. {
  202. return hr;
  203. }
  204. else
  205. {
  206. //
  207. // Read the UUID from the job indicated.
  208. //
  209. BYTE pbBuffer[sizeof(DWORD) + sizeof(UUID)];
  210. DWORD dwBytesRead;
  211. if (!ReadFile(hFile, pbBuffer, sizeof(pbBuffer), &dwBytesRead, NULL))
  212. {
  213. CHECK_HRESULT(HRESULT_FROM_WIN32(GetLastError()));
  214. CloseHandle(hFile);
  215. return SCHED_E_INVALID_TASK;
  216. }
  217. if (dwBytesRead != sizeof(pbBuffer))
  218. {
  219. CHECK_HRESULT(SCHED_E_INVALID_TASK);
  220. CloseHandle(hFile);
  221. return SCHED_E_INVALID_TASK;
  222. }
  223. CopyMemory(pJobID, pbBuffer + sizeof(DWORD), sizeof(*pJobID));
  224. }
  225. //
  226. // Retrieve file creation time and the volume serial number.
  227. //
  228. if (!GetFileInformationByHandle(hFile, &hinfo))
  229. {
  230. hr = HRESULT_FROM_WIN32(GetLastError());
  231. CHECK_HRESULT(hr);
  232. goto ErrorExit;
  233. }
  234. //
  235. // Retrieve the file owner. Call GetFileSecurity twice - first to get
  236. // the buffer size, then the actual information retrieval.
  237. //
  238. if (GetFileSecurity(pwszFileName,
  239. OWNER_SECURITY_INFORMATION,
  240. NULL,
  241. 0,
  242. &cbSizeNeeded))
  243. {
  244. //
  245. // Didn't expect this to succeed!
  246. //
  247. hr = E_UNEXPECTED;
  248. CHECK_HRESULT(hr);
  249. goto ErrorExit;
  250. }
  251. if ((GetLastError() == ERROR_INSUFFICIENT_BUFFER) && (cbSizeNeeded > 0))
  252. {
  253. //
  254. // Allocate the buffer space necessary and retrieve the info.
  255. //
  256. pOwnerSecDescr = (SECURITY_DESCRIPTOR *)new BYTE[cbSizeNeeded];
  257. if (pOwnerSecDescr == NULL)
  258. {
  259. hr = E_OUTOFMEMORY;
  260. CHECK_HRESULT(hr);
  261. goto ErrorExit;
  262. }
  263. if (!GetFileSecurity(pwszFileName,
  264. OWNER_SECURITY_INFORMATION,
  265. pOwnerSecDescr,
  266. cbSizeNeeded,
  267. &cbSizeNeeded))
  268. {
  269. hr = HRESULT_FROM_WIN32(GetLastError());
  270. CHECK_HRESULT(hr);
  271. goto ErrorExit;
  272. }
  273. }
  274. else
  275. {
  276. hr = HRESULT_FROM_WIN32(GetLastError());
  277. CHECK_HRESULT(hr);
  278. goto ErrorExit;
  279. }
  280. //
  281. // Retrieve & validate the owner sid.
  282. //
  283. // NB : After this, pOwnerSid will point into the security descriptor,
  284. // pOwnerSecDescr; hence, the descriptor must exist for the
  285. // lifetime of pOwnerSid.
  286. //
  287. fRet = GetSecurityDescriptorOwner(pOwnerSecDescr,
  288. &pOwnerSid,
  289. &fOwnerDefaulted);
  290. if (fRet)
  291. {
  292. if (fRet = IsValidSid(pOwnerSid))
  293. {
  294. cbOwnerSid = GetLengthSid(pOwnerSid);
  295. }
  296. else
  297. {
  298. hr = HRESULT_FROM_WIN32(GetLastError());
  299. CHECK_HRESULT(hr);
  300. }
  301. }
  302. else
  303. {
  304. hr = HRESULT_FROM_WIN32(GetLastError());
  305. CHECK_HRESULT(hr);
  306. }
  307. if (!fRet)
  308. {
  309. goto ErrorExit;
  310. }
  311. //
  312. // Retrieve the account name & domain name from the file owner sid.
  313. //
  314. SID_NAME_USE snu;
  315. BOOL bDoLookupAgain;
  316. //
  317. //Startup jobs for domain users will fail if workstation is not initialized
  318. //If LookupAccountSid fails and we are booting then force the service to
  319. // wait until workstation is fully initialized and then try again
  320. //
  321. do
  322. {
  323. bDoLookupAgain = FALSE;
  324. schDebugOut((DEB_TRACE, "GetFileInformation: Calling LookupAccountSid\n"));
  325. if (!LookupAccountSid(NULL,
  326. pOwnerSid,
  327. wszOwnerName,
  328. &ccOwnerName,
  329. wszOwnerDomain,
  330. &ccOwnerDomain,
  331. &snu))
  332. {
  333. hr = HRESULT_FROM_WIN32(GetLastError());
  334. CHECK_HRESULT(hr);
  335. if( s_bWaitForWorkStation )
  336. {
  337. schDebugOut((DEB_TRACE, "GetFileInformation: Delaying LookupAccountSid for boot\n"));
  338. WaitForMUP(120000);
  339. WaitForServiceToStart(L"workstation",120000);
  340. WaitForServiceToStart(L"netlogon",120000);
  341. bDoLookupAgain = TRUE;
  342. s_bWaitForWorkStation = FALSE;
  343. //Reset since CloseFile returns this value if failure
  344. hr = ERROR_SUCCESS;
  345. } else {
  346. goto ErrorExit;
  347. }
  348. }
  349. } while(bDoLookupAgain);
  350. ErrorExit:
  351. //
  352. // Being a little sneaky here and reading the job application whilst
  353. // closing the file handle. That is, if all succeeded above.
  354. //
  355. hr = CloseFile(hFile, (WORD)ccApplication, wszApplication, hr);
  356. if (SUCCEEDED(hr))
  357. {
  358. *pftCreationTime = hinfo.ftCreationTime;
  359. *pdwVolumeSerialNo = hinfo.dwVolumeSerialNumber;
  360. *pcbOwnerSid = cbOwnerSid;
  361. *ppOwnerSid = pOwnerSid;
  362. *ppOwnerSecDescr = pOwnerSecDescr;
  363. //
  364. // If not already done so, set the 'mystery' global DWORD.
  365. // This DWORD, in addition to other data, is used to generate
  366. // the encryption key for the SAC/SAI database.
  367. //
  368. // The reason why this is done here is to spread the key generation
  369. // code around a bit.
  370. //
  371. if (!gdwKeyElement)
  372. {
  373. SetMysteryDWORDValue();
  374. }
  375. }
  376. else
  377. {
  378. delete pOwnerSecDescr;
  379. }
  380. return(hr);
  381. }
  382. //+---------------------------------------------------------------------------
  383. //
  384. // Function: SetMysteryDWORDValue
  385. //
  386. // Synopsis: Initialize a global DWORD to be used as a data element in
  387. // generation of the SAC/SAI database encryption key.
  388. //
  389. // Arguments: None.
  390. //
  391. // Returns: None.
  392. //
  393. // Notes: None.
  394. //
  395. //----------------------------------------------------------------------------
  396. void
  397. SetMysteryDWORDValue(void)
  398. {
  399. //
  400. // Set the global mystery dword to the first dword of the job or queue
  401. // class ids, depending on the value of the machine sid.
  402. //
  403. EnterCriticalSection(&gcsSSCritSection);
  404. if (!gdwKeyElement)
  405. {
  406. DWORD dwTmp;
  407. //
  408. // The last (3) subauthorities of the machine SID are unique per
  409. // machine. Test LSB of the 2nd from the last subauthority.
  410. //
  411. PUCHAR pSidSubAuthorityCount = GetSidSubAuthorityCount(
  412. gpDomainInfo->DomainSid);
  413. schAssert(pSidSubAuthorityCount != NULL);
  414. DWORD nSubAuthority = (pSidSubAuthorityCount != NULL ?
  415. max(*pSidSubAuthorityCount, 2) : 2);
  416. DWORD * pSubAuthority = GetSidSubAuthority(
  417. gpDomainInfo->DomainSid,
  418. nSubAuthority - 2);
  419. schAssert(pSubAuthority != NULL);
  420. if (pSubAuthority != NULL && *pSubAuthority & 0x00000001)
  421. {
  422. dwTmp = 0x255b3f60; // CLSID_CQueue.Data1
  423. }
  424. else
  425. {
  426. dwTmp = CLSID_CTask.Data1;
  427. }
  428. //
  429. // Apply a mask to the mystery value to further disguise it.
  430. //
  431. if (gwszComputerName[0] & 0x0100)
  432. {
  433. dwTmp &= 0xC03F71C3;
  434. }
  435. else
  436. {
  437. dwTmp &= 0xE3507233;
  438. }
  439. gdwKeyElement = dwTmp;
  440. }
  441. LeaveCriticalSection(&gcsSSCritSection);
  442. }
  443. //*************************************************************
  444. //
  445. // WaitForServiceToStart()
  446. //
  447. // Purpose: Waits for the specified service to start
  448. //
  449. // Parameters: dwMaxWait - Max wait time
  450. //
  451. //
  452. // Return: TRUE if the network is started
  453. // FALSE if not
  454. //
  455. //*************************************************************
  456. BOOL WaitForServiceToStart (LPTSTR lpServiceName, DWORD dwMaxWait)
  457. {
  458. BOOL bStarted = FALSE;
  459. DWORD dwSize = 512;
  460. SC_HANDLE hScManager = NULL;
  461. SC_HANDLE hService = NULL;
  462. LPQUERY_SERVICE_CONFIG lpServiceConfig = NULL;
  463. DWORD dwPoleWait = 1000;
  464. DWORD StartTickCount;
  465. SERVICE_STATUS ServiceStatus;
  466. //
  467. // OpenSCManager and the rpcss service
  468. //
  469. hScManager = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
  470. if (!hScManager) {
  471. goto Exit;
  472. }
  473. hService = OpenService(hScManager, lpServiceName,
  474. SERVICE_QUERY_CONFIG | SERVICE_QUERY_STATUS);
  475. if (!hService) {
  476. goto Exit;
  477. }
  478. //
  479. // Query if the service is going to start
  480. //
  481. lpServiceConfig = (LPQUERY_SERVICE_CONFIG)LocalAlloc (LPTR, dwSize);
  482. if (!lpServiceConfig) {
  483. goto Exit;
  484. }
  485. if (!QueryServiceConfig (hService, lpServiceConfig, dwSize, &dwSize)) {
  486. if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
  487. goto Exit;
  488. }
  489. LocalFree (lpServiceConfig);
  490. lpServiceConfig = (LPQUERY_SERVICE_CONFIG)LocalAlloc (LPTR, dwSize);
  491. if (!lpServiceConfig) {
  492. goto Exit;
  493. }
  494. if (!QueryServiceConfig (hService, lpServiceConfig, dwSize, &dwSize)) {
  495. goto Exit;
  496. }
  497. }
  498. if (lpServiceConfig->dwStartType != SERVICE_AUTO_START) {
  499. goto Exit;
  500. }
  501. //
  502. // Loop until the service starts or we think it never will start
  503. // or we've exceeded our maximum time delay.
  504. //
  505. StartTickCount = GetTickCount();
  506. while (!bStarted) {
  507. if ((GetTickCount() - StartTickCount) > dwMaxWait) {
  508. break;
  509. }
  510. if (!QueryServiceStatus(hService, &ServiceStatus )) {
  511. break;
  512. }
  513. if (ServiceStatus.dwCurrentState == SERVICE_STOPPED) {
  514. if (ServiceStatus.dwWin32ExitCode == ERROR_SERVICE_NEVER_STARTED) {
  515. Sleep(dwPoleWait);
  516. } else {
  517. break;
  518. }
  519. } else if ( (ServiceStatus.dwCurrentState == SERVICE_RUNNING) ||
  520. (ServiceStatus.dwCurrentState == SERVICE_CONTINUE_PENDING) ||
  521. (ServiceStatus.dwCurrentState == SERVICE_PAUSE_PENDING) ||
  522. (ServiceStatus.dwCurrentState == SERVICE_PAUSED) ) {
  523. bStarted = TRUE;
  524. } else if (ServiceStatus.dwCurrentState == SERVICE_START_PENDING) {
  525. Sleep(dwPoleWait);
  526. } else {
  527. Sleep(dwPoleWait);
  528. }
  529. }
  530. Exit:
  531. if (lpServiceConfig) {
  532. LocalFree (lpServiceConfig);
  533. }
  534. if (hService) {
  535. CloseServiceHandle(hService);
  536. }
  537. if (hScManager) {
  538. CloseServiceHandle(hScManager);
  539. }
  540. return bStarted;
  541. }
  542. //*************************************************************
  543. //
  544. // WaitForMUP()
  545. //
  546. // Purpose: Waits for the MUP to finish initializing
  547. //
  548. // Parameters: dwMaxWait - Max wait time
  549. //
  550. // Return: TRUE if successful
  551. // FALSE if an error occurs
  552. //
  553. //*************************************************************
  554. BOOL WaitForMUP (DWORD dwMaxWait)
  555. {
  556. HANDLE hEvent = NULL;
  557. BOOL bResult;
  558. INT i = 0;
  559. //
  560. // Try to open the event
  561. //
  562. do {
  563. hEvent = OpenEvent (SYNCHRONIZE, FALSE,
  564. TEXT("wkssvc: MUP finished initializing event"));
  565. if (hEvent) {
  566. break;
  567. }
  568. if (GetLastError() != ERROR_FILE_NOT_FOUND) {
  569. break;
  570. }
  571. Sleep(500);
  572. i++;
  573. } while (i < 20);
  574. if (!hEvent) {
  575. return FALSE;
  576. }
  577. //
  578. // Wait for the event to be signalled
  579. //
  580. bResult = (WaitForSingleObject (hEvent, dwMaxWait) == WAIT_OBJECT_0);
  581. //
  582. // Clean up
  583. //
  584. CloseHandle (hEvent);
  585. return bResult;
  586. }