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.

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