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.

1109 lines
26 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. convert.cpp
  5. Abstract:
  6. SCE APIs to set security on converted drives
  7. The main routine is
  8. exposed via RPC to SCE client (for immediate conversion)
  9. executed as an asynchronous thread spawned by the server during reboot (for scheduled conversion)
  10. Author:
  11. Vishnu Patankar (vishnup) 07-Aug-2000 created
  12. Revision History:
  13. --*/
  14. #include "headers.h"
  15. #include "serverp.h"
  16. #include "winsvcp.h"
  17. #include "userenvp.h"
  18. extern HINSTANCE MyModuleHandle;
  19. DWORD
  20. ScepExamineDriveInformation(
  21. IN PWSTR pszRootDrive,
  22. IN PWSTR LogFileName,
  23. OUT BOOL *pbSetSecurity
  24. );
  25. DWORD
  26. ScepSetDefaultSecurityDocsAndSettings(
  27. );
  28. DWORD
  29. ScepExtractRootDacl(
  30. OUT PSECURITY_DESCRIPTOR *ppSDSet,
  31. OUT PACL *ppDacl,
  32. OUT SECURITY_INFORMATION *pSeInfo
  33. );
  34. VOID
  35. ScepSecureUserProfiles(
  36. IN PWSTR pCurrDrive
  37. );
  38. DWORD
  39. ScepConfigureConvertedFileSecurityImmediate(
  40. IN PWSTR pszDriveName
  41. );
  42. VOID
  43. ScepConfigureConvertedFileSecurityReboot(
  44. IN PVOID pV
  45. )
  46. /*++
  47. Routine Description:
  48. The actual routine to configure setup style security for drives converted from FAT to NTFS.
  49. The following applies foreach volume that is NTFS - otherwise we log an error and continue with
  50. other drives (if any)
  51. First we need to set security on the \Docs&Settings folder if it sits below the drive
  52. under consideration. Upgrade style security configuration for this folder is done by the userenv API
  53. DetermineProfilesLocation(). Also need to read SD - add protected bit to SD - set SD back to \Docs&Settings
  54. such that configuring root with MARTA later will not whack this security. This step is not required if
  55. security set by userenv is diffetent from default FAT security on the root drive (since marta will not
  56. detect inheritance and hence will not whack security on \Docs&Settings). The latter is the more likely
  57. case.
  58. (a) If we are dealing with the system drive
  59. Then we just use the security template
  60. %windir%\security\templates\setup security.inf to configure setup style security (make an RPC
  61. call into scesrv).
  62. (b) If we are dealing with a non system drive (whatever the OS maybe), we just use MARTA APIs to set
  63. security on the root drive (from scecli itself). Currently, this is the design since there is no
  64. reliable way of parsing the boot files (boot.ini/boot.nvr).
  65. Then continue with the next drive as in the reg value.
  66. Since we are doing all this at reboot (scheduled), delete the reg value after we're done.
  67. Note on error reporting:
  68. All errors are logged to the logfile %windir%\security\logs\convert.log. but if it is not possible
  69. to log an error to the logfile, we log it to the event log with source "SceSrv". Also, higher level
  70. errors/successes are logged to both the logfile and the eventlog.
  71. Arguments:
  72. pV - MULTI_SZ drive name(s) argument
  73. Return:
  74. none
  75. --*/
  76. {
  77. //
  78. // arguments for the thread in which this routine executes
  79. //
  80. PWSTR pmszDriveNames = (PWSTR)pV;
  81. //
  82. // Error codes
  83. //
  84. DWORD rc = ERROR_SUCCESS;
  85. DWORD rcSave = ERROR_SUCCESS;
  86. //
  87. // folders to use for logging etc.
  88. //
  89. WCHAR szWinDir[MAX_PATH*2 + 1];
  90. WCHAR LogFileName[MAX_PATH + 1];
  91. WCHAR pszSystemDrive[MAX_PATH];
  92. WCHAR InfFileName[MAX_PATH + 1];
  93. WCHAR DatabaseName[MAX_PATH + 1];
  94. //
  95. // other variables
  96. //
  97. BOOL bSetSecurity = TRUE;
  98. PSECURITY_DESCRIPTOR pSDSet=NULL;
  99. PACL pDacl=NULL;
  100. BOOLEAN bRootDaclExtracted = FALSE;
  101. //
  102. // before attempting to do any useful work, validate arguments for this thread etc.
  103. // todo - should we handle exceptions ?
  104. //
  105. (void) InitializeEvents(L"SceSrv");
  106. if ( pmszDriveNames == NULL) {
  107. //
  108. // should not happen - parameters have been checked by all callers
  109. //
  110. LogEvent(MyModuleHandle,
  111. STATUS_SEVERITY_ERROR,
  112. SCEEVENT_ERROR_CONVERT_PARAMETER,
  113. IDS_ERROR_CONVERT_PARAMETER
  114. );
  115. //(void) ShutdownEvents();
  116. return;
  117. }
  118. pszSystemDrive[0] = L'\0';
  119. //
  120. // ready the log file, logging level etc.
  121. //
  122. //
  123. // logging, database creation (if required) etc. is done in %windir%\security\*
  124. //
  125. szWinDir[0] = L'\0';
  126. if ( GetSystemWindowsDirectory( szWinDir, MAX_PATH ) == 0 ) {
  127. //
  128. // too bad if this happens
  129. //
  130. LogEvent(MyModuleHandle,
  131. STATUS_SEVERITY_ERROR,
  132. SCEEVENT_ERROR_CONVERT_BAD_ENV_VAR,
  133. IDS_ERROR_CONVERT_BAD_ENV_VAR,
  134. L"%windir%"
  135. );
  136. //(void) ShutdownEvents();
  137. return;
  138. }
  139. LogFileName[0] = L'\0';
  140. wcscpy(LogFileName, szWinDir);
  141. wcscat(LogFileName, L"\\security\\logs\\convert.log");
  142. ScepEnableDisableLog(TRUE);
  143. ScepSetVerboseLog(3);
  144. if ( ScepLogInitialize( LogFileName ) == ERROR_INVALID_NAME ) {
  145. ScepLogOutput3(1,0, SCEDLL_LOGFILE_INVALID, LogFileName );
  146. }
  147. //
  148. // continue even if we cannot initialize log file but we absolutely
  149. // need the following environment var, so if we can't get it, quit
  150. //
  151. if ( GetEnvironmentVariable( L"SYSTEMDRIVE", pszSystemDrive, MAX_PATH) == 0 ) {
  152. ScepLogOutput3(0,0, SCEDLL_CONVERT_BAD_ENV_VAR, L"%SYSTEMDRIVE%");
  153. LogEvent(MyModuleHandle,
  154. STATUS_SEVERITY_ERROR,
  155. SCEEVENT_ERROR_CONVERT_BAD_ENV_VAR,
  156. IDS_ERROR_CONVERT_BAD_ENV_VAR,
  157. L"%systemdrive%"
  158. );
  159. ScepLogClose();
  160. //(void) ShutdownEvents();
  161. return;
  162. }
  163. //
  164. // following two will be used only if system drive
  165. //
  166. OSVERSIONINFOEX osVersionInfo;
  167. BYTE ProductType = VER_NT_WORKSTATION;
  168. osVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
  169. if ( GetVersionEx((LPOSVERSIONINFO) &osVersionInfo) ){
  170. ProductType = osVersionInfo.wProductType;
  171. // use osVersionInfo.wSuiteMask when Personal Template Bug is fixed
  172. }
  173. else {
  174. LogEvent(MyModuleHandle,
  175. STATUS_SEVERITY_ERROR,
  176. SCEDLL_CONVERT_PROD_TYPE,
  177. IDS_ERROR_CONVERT_PROD_TYPE,
  178. GetLastError()
  179. );
  180. ScepLogClose();
  181. //(void) ShutdownEvents();
  182. return;
  183. }
  184. //
  185. // use the right template
  186. //
  187. InfFileName[0] = L'\0';
  188. wcscpy(InfFileName, szWinDir);
  189. switch(ProductType){
  190. case VER_NT_WORKSTATION:
  191. wcscat(InfFileName, L"\\inf\\defltwk.inf");
  192. break;
  193. case VER_NT_DOMAIN_CONTROLLER:
  194. wcscat(InfFileName, L"\\inf\\defltdc.inf");
  195. break;
  196. case VER_NT_SERVER:
  197. wcscat(InfFileName, L"\\inf\\defltsv.inf");
  198. break;
  199. default:
  200. //
  201. // won't happen unless API is bad - default to wks
  202. //
  203. wcscat(InfFileName, L"\\inf\\defltwk.inf");
  204. break;
  205. }
  206. DatabaseName[0] = L'\0';
  207. wcscpy(DatabaseName, szWinDir);
  208. wcscat(DatabaseName, L"\\security\\database\\convert.sdb");
  209. //
  210. // condition in the loop will end when it sees the last two \0 s in a
  211. // MULTI_SZ string such as C:\0E:\0\0
  212. //
  213. for (PWSTR pCurrDrive = pmszDriveNames; pCurrDrive[0] != L'\0' ; pCurrDrive += wcslen(pCurrDrive) + 1) {
  214. //
  215. // try next drive if this drive is not securable or if error in querying drive information
  216. //
  217. if (ERROR_SUCCESS != (rc = ScepExamineDriveInformation(pCurrDrive, LogFileName, &bSetSecurity))) {
  218. rcSave = rc;
  219. continue;
  220. }
  221. if (!bSetSecurity) {
  222. //
  223. // reset for next iteration
  224. //
  225. bSetSecurity = TRUE;
  226. continue;
  227. }
  228. ScepLogOutput3(0,0, SCEDLL_CONVERT_ROOT_NTFS_VOLUME, pCurrDrive);
  229. //
  230. // set security on userprofiles directory if root of profile dir == current drive
  231. // ignore if error - template will have ignore entry for Docs&settings
  232. //
  233. ScepSecureUserProfiles(pCurrDrive);
  234. if ( _wcsicmp(pszSystemDrive, pCurrDrive) == 0 ) {
  235. //
  236. // always use the same databases and log files for convert
  237. //
  238. //
  239. // check config options
  240. //
  241. rc = ScepServerConfigureSystem(
  242. InfFileName,
  243. DatabaseName,
  244. LogFileName,
  245. 0,
  246. AREA_FILE_SECURITY
  247. );
  248. if (rc != ERROR_SUCCESS) {
  249. ScepLogOutput3(0,0, SCEDLL_CONVERT_ERROR_TEMPLATE_APPLY, rc, pCurrDrive);
  250. } else {
  251. ScepLogOutput3(0,0, SCEDLL_CONVERT_SUCCESS_TEMPLATE_APPLY, pCurrDrive);
  252. }
  253. //
  254. // for now use MARTA to set root DACL (another possibility is to use root.inf when checked in)
  255. //
  256. }
  257. //
  258. // set root DACL - use MARTA to set security
  259. //
  260. if ( rc == ERROR_SUCCESS ) {
  261. //
  262. // extract DACL once only
  263. //
  264. SECURITY_INFORMATION SeInfo = 0;
  265. if (!bRootDaclExtracted) {
  266. rc = ScepExtractRootDacl(&pSDSet, &pDacl, &SeInfo);
  267. ScepLogOutput3(0,0, SCEDLL_CONVERT_ERROR_DACL, rc, SDDLRoot);
  268. }
  269. if (rc == ERROR_SUCCESS) {
  270. WCHAR szCurrDriveSlashed[MAX_PATH];
  271. memset(szCurrDriveSlashed, '\0', (MAX_PATH) * sizeof(WCHAR));
  272. wcsncpy(szCurrDriveSlashed, pCurrDrive, 5);
  273. wcscat(szCurrDriveSlashed, L"\\");
  274. bRootDaclExtracted = TRUE;
  275. rc = SetNamedSecurityInfo(szCurrDriveSlashed,
  276. SE_FILE_OBJECT,
  277. SeInfo,
  278. NULL,
  279. NULL,
  280. pDacl,
  281. NULL
  282. );
  283. if (rc != ERROR_SUCCESS) {
  284. ScepLogOutput3(0,0, SCEDLL_CONVERT_ERROR_MARTA, rc, szCurrDriveSlashed);
  285. } else {
  286. ScepLogOutput3(0,0, SCEDLL_CONVERT_SUCCESS_MARTA, szCurrDriveSlashed);
  287. }
  288. }
  289. }
  290. if (rc != ERROR_SUCCESS) {
  291. LogEvent(MyModuleHandle,
  292. STATUS_SEVERITY_INFORMATIONAL,
  293. SCEEVENT_INFO_ERROR_CONVERT_DRIVE,
  294. 0,
  295. pCurrDrive
  296. );
  297. } else {
  298. LogEvent(MyModuleHandle,
  299. STATUS_SEVERITY_INFORMATIONAL,
  300. SCEEVENT_INFO_SUCCESS_CONVERT_DRIVE,
  301. 0,
  302. pCurrDrive
  303. );
  304. }
  305. if (rc != ERROR_SUCCESS) {
  306. rcSave = rc;
  307. rc = ERROR_SUCCESS;
  308. }
  309. }
  310. //
  311. // delete the value (done using this value)
  312. //
  313. ScepRegDeleteValue(
  314. HKEY_LOCAL_MACHINE,
  315. SCE_ROOT_PATH,
  316. L"FatNtfsConvertedDrives"
  317. );
  318. if (pSDSet) {
  319. LocalFree(pSDSet);
  320. }
  321. //
  322. // if scheduled, then services.exe allocated space - so free it
  323. //
  324. LocalFree(pmszDriveNames);
  325. ScepLogClose();
  326. //(void) ShutdownEvents();
  327. return;
  328. }
  329. DWORD
  330. ScepExamineDriveInformation(
  331. IN PWSTR pszRootDrive,
  332. IN PWSTR LogFileName,
  333. OUT BOOL *pbSetSecurity
  334. )
  335. /*++
  336. Routine Description:
  337. If drive type is remote or FAT, do not set security.
  338. Arguments:
  339. pszRootDrive - Name of drive (Null terminated)
  340. pbSetSecurity - whether we should attempt to set security on this drive
  341. Return:
  342. win32 error code
  343. --*/
  344. {
  345. UINT DriveType;
  346. DWORD FileSystemFlags;
  347. DWORD rc = ERROR_SUCCESS;
  348. WCHAR pszDriveNameWithSlash[MAX_PATH];
  349. if (pszRootDrive == NULL || pbSetSecurity == NULL) {
  350. return ERROR_INVALID_PARAMETER;
  351. }
  352. //
  353. // drives are of type c:\ only (cannot have drives of type cd:\)
  354. //
  355. memset(pszDriveNameWithSlash, '\0', MAX_PATH * sizeof(WCHAR));
  356. wcsncpy(pszDriveNameWithSlash, pszRootDrive, 5);
  357. wcscat(pszDriveNameWithSlash, L"\\");
  358. //
  359. // detect if the partition is FAT
  360. //
  361. DriveType = GetDriveType(pszDriveNameWithSlash);
  362. if ( DriveType == DRIVE_FIXED ||
  363. DriveType == DRIVE_RAMDISK ) {
  364. if ( GetVolumeInformation(pszDriveNameWithSlash,
  365. NULL,
  366. 0,
  367. NULL,
  368. NULL,
  369. &FileSystemFlags,
  370. NULL,
  371. 0
  372. ) == TRUE ) {
  373. if ( !(FileSystemFlags & FS_PERSISTENT_ACLS) ) {
  374. //
  375. // only set security on NTFS partition
  376. //
  377. ScepLogOutput3(0,0, SCEDLL_CONVERT_ROOT_NON_NTFS, pszRootDrive);
  378. *pbSetSecurity = FALSE;
  379. }
  380. } else {
  381. //
  382. // something is wrong
  383. //
  384. rc = GetLastError();
  385. ScepLogOutput3(0,0, SCEDLL_CONVERT_ROOT_ERROR_QUERY_VOLUME, rc, pszRootDrive);
  386. *pbSetSecurity = FALSE;
  387. }
  388. }
  389. else {
  390. //
  391. // do not set security on remote drives
  392. //
  393. ScepLogOutput3(0,0, SCEDLL_CONVERT_ROOT_NOT_FIXED_VOLUME, pszRootDrive);
  394. *pbSetSecurity = FALSE;
  395. }
  396. return(rc);
  397. }
  398. DWORD
  399. ScepExtractRootDacl(
  400. OUT PSECURITY_DESCRIPTOR *ppSDSet,
  401. OUT PACL *ppDacl,
  402. OUT SECURITY_INFORMATION *pSeInfo
  403. )
  404. /*++
  405. Routine Description:
  406. Extract root dacl (binary) from golden SD in (in text)
  407. Arguments:
  408. ppDacl - pointer to pointer to converted binary dacl
  409. Return:
  410. win32 error code (DWORD)
  411. --*/
  412. {
  413. DWORD rc = ERROR_SUCCESS;
  414. DWORD dwSize=0;
  415. BOOLEAN tFlag;
  416. BOOLEAN aclPresent;
  417. SECURITY_DESCRIPTOR_CONTROL Control=0;
  418. ULONG Revision;
  419. if ( ppSDSet == NULL || ppDacl == NULL || pSeInfo == NULL) {
  420. return ERROR_INVALID_PARAMETER;
  421. }
  422. rc = ConvertTextSecurityDescriptor (SDDLRoot,
  423. ppSDSet,
  424. &dwSize,
  425. pSeInfo
  426. );
  427. if (rc == ERROR_SUCCESS) {
  428. RtlGetControlSecurityDescriptor (
  429. *ppSDSet,
  430. &Control,
  431. &Revision
  432. );
  433. //
  434. // Get DACL address
  435. //
  436. *ppDacl = NULL;
  437. rc = RtlNtStatusToDosError(
  438. RtlGetDaclSecurityDescriptor(
  439. *ppSDSet,
  440. &aclPresent,
  441. ppDacl,
  442. &tFlag));
  443. if (rc == NO_ERROR && !aclPresent )
  444. *ppDacl = NULL;
  445. //
  446. // if error occurs for this one, do not set. return
  447. //
  448. if ( Control & SE_DACL_PROTECTED ) {
  449. *pSeInfo |= PROTECTED_DACL_SECURITY_INFORMATION;
  450. }
  451. }
  452. return rc;
  453. }
  454. VOID
  455. ScepWaitForServicesEventAndConvertSecurityThreadFunc(
  456. IN PVOID pV
  457. )
  458. /*++
  459. Routine Description:
  460. The main purpose of this thread is to wait for the autostart services event and thereafter call
  461. ScepConfigureConvertedFileSecurityThreadFunc to do the real configuration work
  462. Arguments:
  463. pV - thread argument simply passed on to ScepConfigureConvertedFileSecurityThreadFunc
  464. Return:
  465. none
  466. --*/
  467. {
  468. HANDLE hConvertCanStartEvent = NULL;
  469. DWORD Status;
  470. WCHAR szWinDir[MAX_PATH*2 + 1];
  471. WCHAR LogFileName[MAX_PATH + 1];
  472. szWinDir[0] = L'\0';
  473. if ( GetSystemWindowsDirectory( szWinDir, MAX_PATH ) == 0 ) {
  474. //
  475. // too bad if this happens - can't log anwhere
  476. //
  477. return;
  478. }
  479. //
  480. // same log file is used by this thread as well as the actual configuration
  481. // routine ScepConfigureConvertedFileSecurityThreadFunc (without passing handles)
  482. //
  483. LogFileName[0] = L'\0';
  484. wcscpy(LogFileName, szWinDir);
  485. wcscat(LogFileName, L"\\security\\logs\\convert.log");
  486. ScepEnableDisableLog(TRUE);
  487. ScepSetVerboseLog(3);
  488. if ( ScepLogInitialize( LogFileName ) == ERROR_INVALID_NAME ) {
  489. ScepLogOutput3(1,0, SCEDLL_LOGFILE_INVALID, LogFileName );
  490. }
  491. hConvertCanStartEvent = OpenEvent(
  492. SYNCHRONIZE,
  493. FALSE,
  494. SC_AUTOSTART_EVENT_NAME
  495. );
  496. if (hConvertCanStartEvent == NULL) {
  497. ScepLogOutput3(0,0, SCEDLL_CONVERT_ERROR_EVENT_HANDLE, GetLastError(), SC_AUTOSTART_EVENT_NAME);
  498. if (pV) {
  499. LocalFree(pV);
  500. }
  501. ScepLogClose();
  502. return;
  503. }
  504. //
  505. // timeout after 10 mins
  506. //
  507. Status = WaitForSingleObjectEx(
  508. hConvertCanStartEvent,
  509. 10*60*1000,
  510. FALSE
  511. );
  512. //
  513. // done using the handle
  514. //
  515. CloseHandle(hConvertCanStartEvent);
  516. if (Status == WAIT_OBJECT_0) {
  517. ScepLogOutput3(0,0, SCEDLL_CONVERT_SUCCESS_EVENT_WAIT, SC_AUTOSTART_EVENT_NAME);
  518. //
  519. // close the log file - since ScepConfigureConvertedFileSecurityThreadFunc will
  520. // need to open a handle to the same log file
  521. //
  522. ScepLogClose();
  523. ScepConfigureConvertedFileSecurityReboot(pV);
  524. } else {
  525. ScepLogOutput3(0,0, SCEDLL_CONVERT_ERROR_EVENT_WAIT, RtlNtStatusToDosError(Status), SC_AUTOSTART_EVENT_NAME);
  526. ScepLogClose();
  527. }
  528. ExitThread(RtlNtStatusToDosError(Status));
  529. return;
  530. }
  531. VOID
  532. ScepSecureUserProfiles(
  533. PWSTR pCurrDrive
  534. )
  535. /*++
  536. Routine Description:
  537. Configure Docs&Settings and folders under it
  538. Arguments:
  539. None
  540. Return:
  541. win32Error code
  542. --*/
  543. {
  544. DWORD rc = ERROR_SUCCESS;
  545. WCHAR szProfilesDir[MAX_PATH + 1];
  546. szProfilesDir[0] = L'\0';
  547. BOOL bSecureUserProfiles = TRUE;
  548. if (pCurrDrive == NULL) {
  549. return;
  550. }
  551. DWORD dwLen = MAX_PATH;
  552. //
  553. // don't care for error translating this environment variable -
  554. // just log and continue
  555. //
  556. if ( GetProfilesDirectory(szProfilesDir, &dwLen ) ){
  557. //
  558. // both strings are NULL terminated
  559. //
  560. ULONG uPosition;
  561. for ( uPosition = 0;
  562. szProfilesDir[uPosition] != L'\0' &&
  563. pCurrDrive[uPosition] != L'\0' &&
  564. szProfilesDir[uPosition] != L':' &&
  565. pCurrDrive[uPosition] != L':' &&
  566. towlower(szProfilesDir[uPosition]) == towlower(pCurrDrive[uPosition]);
  567. uPosition++ );
  568. if (!(uPosition > 0 &&
  569. szProfilesDir[uPosition] == L':' &&
  570. pCurrDrive[uPosition] == L':')) {
  571. //
  572. // only if mismatch happened, do not set user profiles
  573. //
  574. bSecureUserProfiles = FALSE;
  575. }
  576. }
  577. else {
  578. ScepLogOutput3(0,0, SCEDLL_CONVERT_BAD_ENV_VAR, L"%USERPROFILE%");
  579. }
  580. if ( bSecureUserProfiles ) {
  581. //
  582. // DetermineProfilesLocation secures Docs&Settings
  583. // SecureUserProfiles() secures folders under Docs&Settings
  584. //
  585. if ( DetermineProfilesLocation(FALSE) ){
  586. SecureUserProfiles();
  587. }
  588. else {
  589. rc = GetLastError();
  590. }
  591. }
  592. if ( bSecureUserProfiles ) {
  593. if ( rc == ERROR_SUCCESS ) {
  594. ScepLogOutput3(0,0, SCEDLL_CONVERT_SUCCESS_PROFILES_DIR, pCurrDrive);
  595. } else {
  596. ScepLogOutput3(0,0, SCEDLL_CONVERT_ERROR_PROFILES_DIR, rc, pCurrDrive);
  597. }
  598. }
  599. return;
  600. }
  601. DWORD
  602. ScepConfigureConvertedFileSecurityImmediate(
  603. IN PWSTR pszDriveName
  604. )
  605. /*++
  606. Routine Description:
  607. The actual routine to configure setup style security for drives converted from FAT to NTFS.
  608. We are dealing only with a non system drive (whatever the OS maybe), we just use MARTA APIs to set
  609. security on the root drive (from scecli itself). Currently, this is the design since there is no
  610. reliable way of parsing the boot files (boot.ini/boot.nvr) and take care of dual boot scenarios.
  611. Note on error reporting:
  612. All errors are logged to the logfile %windir%\security\logs\convert.log. but if it is not possible
  613. to log an error to the logfile, we log it to the event log with source "SceSrv". Also, higher level
  614. errors/successes are logged to both the logfile and the eventlog.
  615. Note that this routine could be done in the client but due to commonality of the error logging,
  616. functionality etc, an RPC call is made to the server
  617. Arguments:
  618. pszDriveName - Name of the volume to be converted
  619. (not freed by services.exe - freed by convert.exe)
  620. Return:
  621. win32 error code
  622. --*/
  623. {
  624. DWORD rc = ERROR_SUCCESS;
  625. DWORD rcSave = ERROR_SUCCESS;
  626. //
  627. // folders to use for logging etc.
  628. //
  629. WCHAR szWinDir[MAX_PATH*2 + 1];
  630. WCHAR LogFileName[MAX_PATH + 1];
  631. WCHAR pszSystemDrive[MAX_PATH];
  632. //
  633. // other variables
  634. //
  635. BOOL bImmediate;
  636. BOOL bSetSecurity = TRUE;
  637. PSECURITY_DESCRIPTOR pSDSet=NULL;
  638. PACL pDacl=NULL;
  639. BOOLEAN bRootDaclExtracted = FALSE;
  640. //
  641. // before attempting to do any useful work, validate arguments for this thread etc.
  642. // todo - should we handle exceptions ?
  643. //
  644. (void) InitializeEvents(L"SceSrv");
  645. if (pszDriveName == NULL) {
  646. //
  647. // should not happen - parameters have been checked by all callers
  648. //
  649. LogEvent(MyModuleHandle,
  650. STATUS_SEVERITY_ERROR,
  651. SCEEVENT_ERROR_CONVERT_PARAMETER,
  652. IDS_ERROR_CONVERT_PARAMETER
  653. );
  654. //(void) ShutdownEvents();
  655. return ERROR_INVALID_PARAMETER;
  656. }
  657. pszSystemDrive[0] = L'\0';
  658. //
  659. // ready the log file, logging level etc.
  660. //
  661. szWinDir[0] = L'\0';
  662. if ( GetSystemWindowsDirectory( szWinDir, MAX_PATH ) == 0 ) {
  663. //
  664. // too bad if this happens
  665. //
  666. LogEvent(MyModuleHandle,
  667. STATUS_SEVERITY_ERROR,
  668. SCEEVENT_ERROR_CONVERT_BAD_ENV_VAR,
  669. IDS_ERROR_CONVERT_BAD_ENV_VAR,
  670. L"%windir%"
  671. );
  672. //(void) ShutdownEvents();
  673. return ERROR_ENVVAR_NOT_FOUND;
  674. }
  675. LogFileName[0] = L'\0';
  676. wcscpy(LogFileName, szWinDir);
  677. wcscat(LogFileName, L"\\security\\logs\\convert.log");
  678. ScepEnableDisableLog(TRUE);
  679. ScepSetVerboseLog(3);
  680. if ( ScepLogInitialize( LogFileName ) == ERROR_INVALID_NAME ) {
  681. ScepLogOutput3(1,0, SCEDLL_LOGFILE_INVALID, LogFileName );
  682. }
  683. //
  684. // continue even if we cannot initialize log file but we absolutely
  685. // need the following environment var, so if we can't get it, quit
  686. //
  687. if ( GetEnvironmentVariable( L"SYSTEMDRIVE", pszSystemDrive, MAX_PATH) == 0 ) {
  688. ScepLogOutput3(0,0, SCEDLL_CONVERT_BAD_ENV_VAR, L"%SYSTEMDRIVE%");
  689. LogEvent(MyModuleHandle,
  690. STATUS_SEVERITY_ERROR,
  691. SCEEVENT_ERROR_CONVERT_BAD_ENV_VAR,
  692. IDS_ERROR_CONVERT_BAD_ENV_VAR,
  693. L"%systemdrive%"
  694. );
  695. ScepLogClose();
  696. //(void) ShutdownEvents();
  697. return ERROR_ENVVAR_NOT_FOUND;
  698. }
  699. //
  700. // called immediately (not reboot/scheduled conversion)
  701. // template never used here - only marta
  702. //
  703. PWSTR pCurrDrive = pszDriveName;
  704. rc = ScepExamineDriveInformation(pCurrDrive, LogFileName, &bSetSecurity);
  705. if (rc == ERROR_SUCCESS && bSetSecurity) {
  706. ScepLogOutput3(0,0, SCEDLL_CONVERT_ROOT_NTFS_VOLUME, pCurrDrive);
  707. //
  708. // set security on userprofiles directory if root of profile dir == current drive
  709. //
  710. ScepSecureUserProfiles(pCurrDrive);
  711. //
  712. // non system drive - use MARTA to set security
  713. //
  714. //
  715. // extract DACL once only, potentially for multiple "other-OS" drives
  716. //
  717. SECURITY_INFORMATION SeInfo = 0;
  718. if (!bRootDaclExtracted) {
  719. rc = ScepExtractRootDacl(&pSDSet, &pDacl, &SeInfo);
  720. ScepLogOutput3(0,0, SCEDLL_CONVERT_ERROR_DACL, rc, SDDLRoot);
  721. }
  722. if (rc == ERROR_SUCCESS) {
  723. WCHAR szCurrDriveSlashed[MAX_PATH];
  724. szCurrDriveSlashed[0] = L'\0';
  725. wcscpy(szCurrDriveSlashed, pCurrDrive);
  726. wcscat(szCurrDriveSlashed, L"\\");
  727. bRootDaclExtracted = TRUE;
  728. rc = SetNamedSecurityInfo(szCurrDriveSlashed,
  729. SE_FILE_OBJECT,
  730. SeInfo,
  731. NULL,
  732. NULL,
  733. pDacl,
  734. NULL
  735. );
  736. if (rc != ERROR_SUCCESS) {
  737. ScepLogOutput3(0,0, SCEDLL_CONVERT_ERROR_MARTA, rc, szCurrDriveSlashed);
  738. } else {
  739. ScepLogOutput3(0,0, SCEDLL_CONVERT_SUCCESS_MARTA, szCurrDriveSlashed);
  740. }
  741. }
  742. }
  743. if (rc != ERROR_SUCCESS) {
  744. LogEvent(MyModuleHandle,
  745. STATUS_SEVERITY_INFORMATIONAL,
  746. SCEEVENT_INFO_ERROR_CONVERT_DRIVE,
  747. 0,
  748. pCurrDrive
  749. );
  750. } else {
  751. LogEvent(MyModuleHandle,
  752. STATUS_SEVERITY_INFORMATIONAL,
  753. SCEEVENT_INFO_SUCCESS_CONVERT_DRIVE,
  754. 0,
  755. pCurrDrive
  756. );
  757. }
  758. if (rc != ERROR_SUCCESS) {
  759. rcSave = rc;
  760. }
  761. if (pSDSet) {
  762. LocalFree(pSDSet);
  763. }
  764. ScepLogClose();
  765. //(void) ShutdownEvents();
  766. // return rcSave;
  767. return rc ;
  768. }