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.

760 lines
23 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1993.
  5. //
  6. // File: globals.cxx
  7. //
  8. // Contents: Service global data.
  9. //
  10. // Classes: None.
  11. //
  12. // Functions: None.
  13. //
  14. // History: 09-Sep-95 EricB Created.
  15. // 01-Dec-95 MarkBl Split from util.cxx.
  16. //
  17. //----------------------------------------------------------------------------
  18. #include "..\pch\headers.hxx"
  19. #pragma hdrstop
  20. #include <sddl.h>
  21. #include "..\inc\resource.h"
  22. #include "..\inc\common.hxx"
  23. #include "..\inc\debug.hxx"
  24. #include "..\inc\misc.hxx"
  25. #include "..\inc\security.hxx"
  26. void
  27. GetRootPath(
  28. LPCWSTR pwszPath,
  29. WCHAR wszRootPath[]);
  30. TasksFolderInfo g_TasksFolderInfo = { NULL, FILESYSTEM_FAT };
  31. TCHAR g_tszSrvcName[] = SCHED_SERVICE_NAME;
  32. BOOL g_fNotifyMiss; // = 0 by loader
  33. HINSTANCE g_hInstance; // = NULL by loader
  34. HANDLE g_hActCtx; // = NULL by loader
  35. ULONG CDll::s_cObjs; // = 0 by loader
  36. ULONG CDll::s_cLocks; // = 0 by loader
  37. WCHAR g_wszAtJobSearchPath[MAX_PATH + 1];
  38. #define DEFAULT_FOLDER_PATH TEXT("%WinDir%\\Tasks")
  39. #define TASKS_FOLDER TEXT("\\Tasks")
  40. //
  41. // BUGBUG: global __int64 initialization is not working without the CRT.
  42. // BUG # 37752.
  43. //
  44. __int64 FILETIMES_PER_DAY;
  45. //+----------------------------------------------------------------------------
  46. //
  47. // Function: InitGlobals
  48. //
  49. // Synopsis: constructs global strings including the folder path strings and,
  50. // if needed, creates the folders
  51. //
  52. // Returns: HRESULTS
  53. //
  54. // Notes: This function is called in exactly two places, once for each
  55. // binary: in dllmisc.cxx for the DLL and in svc_core.cxx for the
  56. // service.
  57. //-----------------------------------------------------------------------------
  58. HRESULT
  59. InitGlobals(void)
  60. {
  61. HRESULT hr = S_OK;
  62. hr = GetTasksFolder(&g_TasksFolderInfo.ptszPath);
  63. if (FAILED(hr))
  64. {
  65. return hr;
  66. }
  67. //
  68. // if the Jobs folder doesn't exist, create it and set security
  69. //
  70. hr = EnsureTasksFolderExists(g_TasksFolderInfo.ptszPath);
  71. if (FAILED(hr))
  72. {
  73. return hr;
  74. }
  75. //
  76. // Initialize the file system type global task folder info field.
  77. //
  78. hr = GetFileSystemTypeFromPath(g_TasksFolderInfo.ptszPath,
  79. &g_TasksFolderInfo.FileSystemType);
  80. if (FAILED(hr))
  81. {
  82. return hr;
  83. }
  84. schDebugOut((DEB_ITRACE,
  85. "Path to local sched folder: \"" FMT_TSTR "\"\n",
  86. g_TasksFolderInfo.ptszPath));
  87. //
  88. // Read the "NotifyOnTaskMiss" value. Default value is 0.
  89. //
  90. hr = GetNotifyOnTaskMiss(&g_fNotifyMiss);
  91. if (FAILED(hr))
  92. {
  93. return hr;
  94. }
  95. //
  96. // Create the AT task FindFirstFile filespec
  97. //
  98. ULONG cchAtJobSearchPath;
  99. cchAtJobSearchPath = lstrlen(g_TasksFolderInfo.ptszPath) +
  100. ARRAY_LEN(TSZ_AT_JOB_PREFIX) - 1 +
  101. ARRAY_LEN(TSZ_DOTJOB) - 1 +
  102. 3; // backslash, start, and nul terminator
  103. if (cchAtJobSearchPath > ARRAY_LEN(g_wszAtJobSearchPath))
  104. {
  105. schDebugOut((DEB_ERROR,
  106. "InitGlobals: At job search path is %u chars but dest buffer is %u\n",
  107. cchAtJobSearchPath,
  108. ARRAY_LEN(g_wszAtJobSearchPath)));
  109. return E_FAIL;
  110. }
  111. StringCchCopy(g_wszAtJobSearchPath, MAX_PATH + 1, g_TasksFolderInfo.ptszPath);
  112. StringCchCat(g_wszAtJobSearchPath, MAX_PATH + 1, L"\\" TSZ_AT_JOB_PREFIX L"*" TSZ_DOTJOB);
  113. //
  114. // BUGBUG: This is temporary until global __int64 initialization is working
  115. // without the CRT:
  116. //
  117. FILETIMES_PER_DAY = (__int64)FILETIMES_PER_MINUTE *
  118. (__int64)JOB_MINS_PER_HOUR *
  119. (__int64)JOB_HOURS_PER_DAY;
  120. return S_OK;
  121. }
  122. //+----------------------------------------------------------------------------
  123. //
  124. // Function: FreeGlobals
  125. //
  126. // Synopsis: frees dynamically allocated globals
  127. //
  128. // Notes: This function is called in exactly two places, once for each
  129. // binary: in dllmisc.cxx for the DLL and in svc_core.cxx for the
  130. // service.
  131. //-----------------------------------------------------------------------------
  132. void
  133. FreeGlobals(void)
  134. {
  135. if (g_TasksFolderInfo.ptszPath != NULL)
  136. {
  137. delete g_TasksFolderInfo.ptszPath;
  138. g_TasksFolderInfo.ptszPath = NULL;
  139. }
  140. }
  141. //+----------------------------------------------------------------------------
  142. //
  143. // Function: ReadLastTaskRun
  144. //
  145. // Synopsis: Reads the last task run time from the registry.
  146. //
  147. // Returns: TRUE if successful, FALSE if unsuccessful
  148. //
  149. // Notes:
  150. //
  151. //-----------------------------------------------------------------------------
  152. BOOL
  153. ReadLastTaskRun(SYSTEMTIME * pstLastRun)
  154. {
  155. HKEY hSchedKey;
  156. LONG lErr = RegOpenKeyEx(HKEY_LOCAL_MACHINE, SCH_AGENT_KEY, 0, KEY_READ,
  157. &hSchedKey);
  158. if (lErr != ERROR_SUCCESS)
  159. {
  160. ERR_OUT("RegOpenKeyEx of Sched key", lErr);
  161. return FALSE;
  162. }
  163. DWORD cb = sizeof SYSTEMTIME;
  164. DWORD dwType;
  165. lErr = RegQueryValueEx(hSchedKey, SCH_LASTRUN_VALUE, NULL, &dwType,
  166. (LPBYTE)pstLastRun, &cb);
  167. RegCloseKey(hSchedKey);
  168. if (lErr != ERROR_SUCCESS || dwType != REG_BINARY || cb != sizeof SYSTEMTIME)
  169. {
  170. schDebugOut((DEB_ERROR, "RegQueryValueEx of LastRunTime value failed, "
  171. "error %ld, dwType = %lu, cb = %lu\n",
  172. lErr, dwType, cb));
  173. return FALSE;
  174. }
  175. return TRUE;
  176. }
  177. //+----------------------------------------------------------------------------
  178. //
  179. // Function: WriteLastTaskRun
  180. //
  181. // Synopsis: Writes the last task run time to the registry.
  182. //
  183. // Returns: TRUE if successful, FALSE if unsuccessful
  184. //
  185. // Notes:
  186. //
  187. //-----------------------------------------------------------------------------
  188. void WriteLastTaskRun(const SYSTEMTIME * pstLastRun)
  189. {
  190. HKEY hSchedKey;
  191. LONG lErr = RegOpenKeyEx(HKEY_LOCAL_MACHINE, SCH_AGENT_KEY, 0, KEY_WRITE,
  192. &hSchedKey);
  193. if (lErr != ERROR_SUCCESS)
  194. {
  195. ERR_OUT("RegOpenKeyEx of Sched key for write", lErr);
  196. return;
  197. }
  198. lErr = RegSetValueEx(hSchedKey, SCH_LASTRUN_VALUE, 0, REG_BINARY,
  199. (const BYTE *) pstLastRun, sizeof SYSTEMTIME);
  200. if (lErr != ERROR_SUCCESS)
  201. {
  202. schDebugOut((DEB_ERROR, "RegSetValueEx of LastRunTime value failed %ld\n",
  203. lErr));
  204. }
  205. RegCloseKey(hSchedKey);
  206. }
  207. //+---------------------------------------------------------------------------
  208. //
  209. // Function: GetFileSystemTypeFromPath
  210. //
  211. // Synopsis: Determine the file system type, either FAT or NTFS, from
  212. // the path passed.
  213. //
  214. // Arguments: [pwszPath] -- Input path.
  215. // [wszRootPath] -- Returned root path.
  216. //
  217. // Returns: S_OK
  218. // GetVolumeInformation HRESULT error code.
  219. //
  220. // Notes: None.
  221. //
  222. //----------------------------------------------------------------------------
  223. HRESULT
  224. GetFileSystemTypeFromPath(LPCWSTR pwszPath, FILESYSTEMTYPE * pFileSystemType)
  225. {
  226. #define FS_NTFS L"NTFS"
  227. #define FS_NAME_BUFFER_SIZE (sizeof(FS_NTFS) * 2)
  228. //
  229. // Obtain the root path (eg: "r:\", "\\fido\scratch\", etc.) from the
  230. // path.
  231. //
  232. LPWSTR pwszRootPath = new WCHAR[wcslen(pwszPath) + 2];
  233. if (pwszRootPath == NULL)
  234. {
  235. CHECK_HRESULT(HRESULT_FROM_WIN32(GetLastError()));
  236. return E_OUTOFMEMORY;
  237. }
  238. GetRootPath(pwszPath, pwszRootPath);
  239. //
  240. // Retrieve the file system name.
  241. //
  242. WCHAR wszFileSystemName[FS_NAME_BUFFER_SIZE + 1];
  243. DWORD dwMaxCompLength, dwFileSystemFlags;
  244. if (!GetVolumeInformation(pwszRootPath, // Root path name.
  245. NULL, // Ignore name.
  246. 0,
  247. NULL, // Ignore serial no.
  248. &dwMaxCompLength, // Unused.
  249. &dwFileSystemFlags, // Unused.
  250. wszFileSystemName, // "FAT"/"NTFS".
  251. FS_NAME_BUFFER_SIZE)) // name buffer size.
  252. {
  253. HRESULT hr = HRESULT_FROM_WIN32(GetLastError());
  254. CHECK_HRESULT(hr);
  255. delete [] pwszRootPath;
  256. return hr;
  257. }
  258. delete [] pwszRootPath;
  259. //
  260. // Check if the volume is NTFS.
  261. // If not NTFS, assume FAT.
  262. //
  263. if (_wcsicmp(wszFileSystemName, FS_NTFS) == 0)
  264. {
  265. *pFileSystemType = FILESYSTEM_NTFS;
  266. }
  267. else
  268. {
  269. *pFileSystemType = FILESYSTEM_FAT;
  270. }
  271. return(S_OK);
  272. }
  273. //+---------------------------------------------------------------------------
  274. //
  275. // Function: GetRootPath
  276. //
  277. // Synopsis: Return the root portion of the path indicated. eg: return
  278. // "r:\" from "r:\foo\bar"
  279. // "\\fido\scratch\", from "\\fido\scratch\bar\foo"
  280. //
  281. // Arguments: [pwszPath] -- Input path.
  282. // [wszRootPath] -- Returned root path.
  283. //
  284. // Returns: None.
  285. //
  286. // Notes: None.
  287. //
  288. //----------------------------------------------------------------------------
  289. void
  290. GetRootPath(LPCWSTR pwszPath, WCHAR wszRootPath[])
  291. {
  292. LPCWSTR pwsz = pwszPath;
  293. if (*pwsz == L'\\')
  294. {
  295. if (*(++pwsz) == L'\\')
  296. {
  297. //
  298. // UNC path. GetVolumeInformation requires the trailing '\'
  299. // on the UNC path. eg: \\server\share\.
  300. //
  301. DWORD i;
  302. for (i = 0, pwsz++; *pwsz && i < 2; i++, pwsz++)
  303. {
  304. for ( ; *pwsz && *pwsz != L'\\'; pwsz++) ;
  305. }
  306. if (i == 2)
  307. {
  308. pwsz--;
  309. }
  310. else
  311. {
  312. goto ErrorExit;
  313. }
  314. }
  315. else
  316. {
  317. //
  318. // Path is "\". Not an error, but handled the same way
  319. //
  320. goto ErrorExit;
  321. }
  322. }
  323. else
  324. {
  325. for ( ; *pwsz && *pwsz != L'\\'; pwsz++) ;
  326. }
  327. if (*pwsz == L'\\')
  328. {
  329. DWORD cbLen = (DWORD)((BYTE *)pwsz - (BYTE *)pwszPath) + sizeof(L'\\');
  330. CopyMemory((LPWSTR)wszRootPath, (LPWSTR)pwszPath, cbLen);
  331. wszRootPath[cbLen / sizeof(WCHAR)] = L'\0';
  332. return;
  333. }
  334. else
  335. {
  336. //
  337. // Fall through.
  338. //
  339. }
  340. ErrorExit:
  341. //
  342. // Return '\' in error cases.
  343. //
  344. wszRootPath[0] = L'\\';
  345. wszRootPath[1] = L'\0';
  346. }
  347. //+---------------------------------------------------------------------------
  348. //
  349. // Function: GetTasksFolder
  350. //
  351. // Synopsis: Get tasks folder setting from registry
  352. //
  353. // Arguments: [ppwszPath] -- pointer to pointer to WCHAR string to receive value
  354. //
  355. // Returns: HRESULT
  356. //
  357. // Notes: The caller of this function will need to delete the allocated memory.
  358. //
  359. //----------------------------------------------------------------------------
  360. HRESULT GetTasksFolder(WCHAR** ppwszPath)
  361. {
  362. HRESULT hr = S_OK;
  363. //
  364. // Open the schedule agent key
  365. //
  366. long lErr;
  367. HKEY hSchedKey = NULL;
  368. lErr = RegOpenKeyEx(HKEY_LOCAL_MACHINE, SCH_AGENT_KEY, 0, KEY_READ, &hSchedKey);
  369. if (lErr != ERROR_SUCCESS)
  370. {
  371. ERR_OUT("RegOpenKeyEx of Scheduler key", lErr);
  372. }
  373. WCHAR wszFolder[MAX_PATH + 1] = L"";
  374. // Ensure null termination (registry doesn't guarantee this if not string data)
  375. wszFolder[MAX_PATH] = L'\0';
  376. if (hSchedKey != NULL)
  377. {
  378. //
  379. // Get the jobs folder location
  380. //
  381. DWORD cb = MAX_PATH * sizeof(WCHAR); // note that this is one less than the actual buffer size
  382. lErr = RegQueryValueEx(hSchedKey, SCH_FOLDER_VALUE, NULL, NULL, (LPBYTE)wszFolder, &cb);
  383. if (lErr != ERROR_SUCCESS)
  384. {
  385. ERR_OUT("RegQueryValueEx of Scheduler TasksFolder value", lErr);
  386. //
  387. // The task folder value is missing, create it.
  388. //
  389. // Reopen the key with write access.
  390. //
  391. RegCloseKey(hSchedKey);
  392. lErr = RegOpenKeyEx(HKEY_LOCAL_MACHINE, SCH_AGENT_KEY, 0, KEY_SET_VALUE, &hSchedKey);
  393. if (lErr != ERROR_SUCCESS)
  394. {
  395. ERR_OUT("RegOpenKeyEx of Scheduler key", lErr);
  396. hSchedKey = NULL;
  397. }
  398. else
  399. {
  400. //
  401. // Default to the windows root.
  402. //
  403. lErr = RegSetValueEx(hSchedKey,
  404. SCH_FOLDER_VALUE,
  405. 0,
  406. REG_EXPAND_SZ,
  407. (const BYTE *) DEFAULT_FOLDER_PATH,
  408. sizeof(DEFAULT_FOLDER_PATH));
  409. if (lErr != ERROR_SUCCESS)
  410. {
  411. ERR_OUT("RegSetValueEx of Scheduler TasksFolder value", lErr);
  412. }
  413. }
  414. }
  415. if (hSchedKey != NULL)
  416. {
  417. RegCloseKey(hSchedKey);
  418. }
  419. }
  420. //
  421. // Use a default if the value is missing.
  422. //
  423. if (lstrlen(wszFolder) == 0)
  424. {
  425. StringCchCopy(wszFolder, MAX_PATH + 1, DEFAULT_FOLDER_PATH);
  426. }
  427. //
  428. // The ExpandEnvironmentStrings character counts include the terminating null.
  429. //
  430. DWORD cch = ExpandEnvironmentStrings(wszFolder, NULL, 0);
  431. if (!cch)
  432. {
  433. hr = HRESULT_FROM_WIN32(GetLastError());
  434. ERR_OUT("ExpandEnvironmentStrings", hr);
  435. return hr;
  436. }
  437. //
  438. // Caller will need to delete this
  439. //
  440. *ppwszPath = new WCHAR[cch];
  441. if (*ppwszPath == NULL)
  442. {
  443. ERR_OUT("Tasks Folder name buffer allocation", E_OUTOFMEMORY);
  444. return E_OUTOFMEMORY;
  445. }
  446. cch = ExpandEnvironmentStrings(wszFolder, *ppwszPath, cch);
  447. if (!cch)
  448. {
  449. hr = HRESULT_FROM_WIN32(GetLastError());
  450. ERR_OUT("ExpandEnvironmentStrings", hr);
  451. return hr;
  452. }
  453. return hr;
  454. }
  455. //+---------------------------------------------------------------------------
  456. //
  457. // Function: GetNotifyOnTaskMiss
  458. //
  459. // Synopsis: Get NotifyOnTaskMiss setting from registry
  460. //
  461. // Arguments: [pfNotifyOnTaskMiss] -- pointer to boolean flag to receive value
  462. //
  463. // Returns: HRESULT
  464. //
  465. //----------------------------------------------------------------------------
  466. HRESULT GetNotifyOnTaskMiss(BOOL* pfNotifyOnTaskMiss)
  467. {
  468. HRESULT hr = S_OK;
  469. if (!pfNotifyOnTaskMiss)
  470. return E_INVALIDARG;
  471. //
  472. // default value in case it can't be retrieved from registry
  473. //
  474. *pfNotifyOnTaskMiss = 0;
  475. //
  476. // Open the schedule agent key
  477. //
  478. long lErr;
  479. HKEY hSchedKey = NULL;
  480. lErr = RegOpenKeyEx(HKEY_LOCAL_MACHINE, SCH_AGENT_KEY, 0, KEY_READ, &hSchedKey);
  481. if (lErr != ERROR_SUCCESS)
  482. {
  483. ERR_OUT("RegOpenKeyEx of Scheduler key", lErr);
  484. }
  485. if (hSchedKey != NULL)
  486. {
  487. //
  488. // Read the "NotifyOnTaskMiss" value. Default value is 0.
  489. //
  490. DWORD cb = sizeof BOOL; // size of *pfNotifyOnTaskMiss
  491. lErr = RegQueryValueEx(hSchedKey, SCH_NOTIFYMISS_VALUE, NULL, NULL, (LPBYTE) pfNotifyOnTaskMiss, &cb);
  492. if (lErr != ERROR_SUCCESS)
  493. {
  494. if (lErr != ERROR_FILE_NOT_FOUND)
  495. {
  496. ERR_OUT("RegQueryValueEx of NotifyOnTaskMiss value", lErr);
  497. }
  498. }
  499. schDebugOut((DEB_TRACE, "Notification of missed runs is %s\n",
  500. *pfNotifyOnTaskMiss ? "enabled" : "disabled"));
  501. RegCloseKey(hSchedKey);
  502. }
  503. return hr;
  504. }
  505. //+---------------------------------------------------------------------------
  506. //
  507. // Function: CreateDesktopIni
  508. //
  509. // Synopsis: Create the desktop.ini file in the Tasks folder.
  510. //
  511. // Arguments: [pwszFolderPath] -- Path to the Tasks folder.
  512. //
  513. // Returns: S_OK
  514. // E_UNEXPECTED if the amount written isn't what we expected.
  515. // Create/WriteFile HRESULT status code on failure.
  516. //
  517. //----------------------------------------------------------------------------
  518. HRESULT CreateDesktopIni(LPCWSTR pwszFolderPath)
  519. {
  520. HRESULT hr = S_OK;
  521. //
  522. // Create the file
  523. //
  524. WCHAR wszDesktopIniPath[MAX_PATH + 1];
  525. StringCchCopy(wszDesktopIniPath, MAX_PATH + 1, pwszFolderPath);
  526. StringCchCat(wszDesktopIniPath, MAX_PATH + 1, L"\\desktop.ini");
  527. HANDLE hFile = CreateFile(wszDesktopIniPath,
  528. GENERIC_WRITE,
  529. FILE_SHARE_READ,
  530. NULL,
  531. CREATE_NEW,
  532. FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_READONLY,
  533. NULL);
  534. if (hFile == INVALID_HANDLE_VALUE)
  535. {
  536. hr = HRESULT_FROM_WIN32(GetLastError());
  537. CHECK_HRESULT(hr);
  538. return hr;
  539. }
  540. //
  541. // Write out the contents.
  542. //
  543. char szFileContents[66] = "[.ShellClassInfo]\r\nCLSID={d6277990-4c6a-11cf-8d87-00aa0060f5bf}\r\n";
  544. DWORD cbToWrite = (66 - 1) * sizeof(char);
  545. DWORD cbWritten;
  546. if (!WriteFile(hFile, &szFileContents, cbToWrite, &cbWritten, NULL) || cbWritten != cbToWrite)
  547. {
  548. hr = HRESULT_FROM_WIN32(GetLastError());
  549. CHECK_HRESULT(hr);
  550. }
  551. CloseHandle(hFile);
  552. return hr;
  553. }
  554. //+---------------------------------------------------------------------------
  555. //
  556. // Function: EnsureTasksFolderExists
  557. //
  558. // Synopsis: Check that the folder is there;
  559. // if not then create it and set security appropriately
  560. //
  561. // Arguments: [pwszPath] -- path to tasks folder
  562. // [bEnableShellExtension] -- indicate whether we are to make this
  563. // folder use our shell extenstion when viewed via explorer. Default
  564. // is TRUE if not specified. It should be FALSE if this function
  565. // is being used to recreate a folder only used for logging.
  566. //
  567. // Returns: HRESULT
  568. //
  569. //----------------------------------------------------------------------------
  570. HRESULT EnsureTasksFolderExists(LPWSTR pwszPath, BOOL bEnableShellExtension /* = TRUE */)
  571. {
  572. HRESULT hr = S_OK;
  573. //
  574. // check that the folder is there, if not then create it and set security appropriately
  575. //
  576. DWORD dwAttribs = GetFileAttributes(pwszPath);
  577. if (0xFFFFFFFF == dwAttribs)
  578. {
  579. PSECURITY_DESCRIPTOR pSD = NULL;
  580. WCHAR* pwszSDDL = NULL;
  581. OSVERSIONINFOEX verInfo;
  582. verInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
  583. if (!GetVersionEx((LPOSVERSIONINFOW)&verInfo))
  584. return E_FAIL;
  585. if (verInfo.wProductType == VER_NT_WORKSTATION)
  586. pwszSDDL =
  587. L"D:P(A;OICIIO;FA;;;CO)(A;;0x1200ab;;;AU)(A;OICI;FA;;;BA)(A;OICI;FA;;;SY)"
  588. L"S:(AU;SAFAOICI;FWDCSDWDWO;;;WD)(AU;SAFAOICI;FWDCSDWDWO;;;AN)";
  589. else
  590. pwszSDDL =
  591. L"D:P(A;OICIIO;FA;;;CO)(A;;0x1200ab;;;BO)(A;;0x1200ab;;;SO)(A;OICI;FA;;;BA)(A;OICI;FA;;;SY)"
  592. L"S:(AU;SAFAOICI;FWDCSDWDWO;;;WD)(AU;SAFAOICI;FWDCSDWDWO;;;AN)";
  593. //
  594. // generate SD to be used for tasks folder
  595. //
  596. if (!ConvertStringSecurityDescriptorToSecurityDescriptorW(pwszSDDL, SDDL_REVISION_1, &pSD, NULL))
  597. {
  598. hr = HRESULT_FROM_WIN32(GetLastError());
  599. ERR_OUT("ConvertStringSecurityDescriptorToSecurityDescriptorW", hr);
  600. }
  601. if (SUCCEEDED(hr))
  602. {
  603. //
  604. // Enable SecurityPrivilege in order to be able to set the SACL
  605. //
  606. BOOL bWasEnabled = FALSE;
  607. DWORD dwErr = EnablePrivilege(SE_SECURITY_NAME, TRUE, &bWasEnabled);
  608. if (ERROR_SUCCESS != dwErr)
  609. {
  610. hr = HRESULT_FROM_WIN32(dwErr);
  611. ERR_OUT("EnablePrivilege", hr);
  612. }
  613. if (SUCCEEDED(hr))
  614. {
  615. SECURITY_ATTRIBUTES saAttributes;
  616. saAttributes.nLength = sizeof(SECURITY_ATTRIBUTES);
  617. saAttributes.lpSecurityDescriptor = pSD;
  618. saAttributes.bInheritHandle = FALSE;
  619. if (!CreateDirectory(pwszPath, &saAttributes))
  620. {
  621. hr = HRESULT_FROM_WIN32(GetLastError());
  622. ERR_OUT("CreateDirectory", hr);
  623. }
  624. if (bEnableShellExtension)
  625. {
  626. //
  627. // Folder must have SYSTEM attribute in order to be treated properly by Explorer
  628. //
  629. if (SUCCEEDED(hr))
  630. {
  631. if (!SetFileAttributes(pwszPath, FILE_ATTRIBUTE_SYSTEM))
  632. {
  633. hr = HRESULT_FROM_WIN32(GetLastError());
  634. ERR_OUT("SetFileAttributes", hr);
  635. }
  636. }
  637. //
  638. // Create the desktop.ini file that specifies the shell class for our extension
  639. //
  640. if (SUCCEEDED(hr))
  641. {
  642. hr = CreateDesktopIni(pwszPath);
  643. }
  644. }
  645. //
  646. // UnEnable SecurityPrivilege if it wasn't originally enabled
  647. //
  648. if (!bWasEnabled)
  649. {
  650. dwErr = EnablePrivilege(SE_SECURITY_NAME, FALSE, 0);
  651. if (ERROR_SUCCESS != dwErr)
  652. {
  653. if (SUCCEEDED(hr))
  654. {
  655. // if above calls were successful then we'll report this error; otherwise,
  656. // the above failure is more interesting so we skip this and return that one.
  657. // either way, an error is going to get returned
  658. hr = HRESULT_FROM_WIN32(dwErr);
  659. ERR_OUT("EnablePrivilege UnEnable", hr);
  660. }
  661. }
  662. }
  663. }
  664. LocalFree(pSD);
  665. }
  666. }
  667. return hr;
  668. }