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.

1591 lines
44 KiB

  1. //+----------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1993.
  5. //
  6. // File: setup.cxx
  7. //
  8. // Contents: Task Scheduler setup program
  9. //
  10. // Classes: None.
  11. //
  12. // Functions:
  13. //
  14. // History: 04-Apr-96 MarkBl Created
  15. // 23-Sep-96 AnirudhS Added SetTaskFolderSecurity, etc.
  16. // 30-Sep-96 AnirudhS Added /firstlogon and /logon options
  17. // 15-Nov-96 AnirudhS Conditionally enable the service on NT too
  18. // 01-09-97 DavidMun Add sysagent.exe path value under
  19. // app paths, backup sysagent.exe
  20. // 04-14-97 DavidMun Add DoMemphisSetup
  21. // 03-03-01 JBenton Prefix BUG 333200 use of uninit memory
  22. // 03-10-01 JBenton BUG 142333 tighten Tasks folder security
  23. //
  24. //-----------------------------------------------------------------------------
  25. #include <windows.h>
  26. #include <regstr.h>
  27. #include <tchar.h>
  28. #include <common.hxx>
  29. #include <security.hxx>
  30. #include "setupids.h"
  31. #if defined(_CHICAGO_)
  32. #include <shlobj.h>
  33. #include <shellapi.h>
  34. #include <shlobjp.h>
  35. #include <dbcs.hxx>
  36. #else // NT
  37. #include <userenv.h>
  38. #include <userenvp.h>
  39. #endif // defined(_CHICAGO_)
  40. #define ARRAY_LEN(a) (sizeof(a)/sizeof((a)[0]))
  41. #define ARG_DELIMITERS TEXT(" \t")
  42. #define MINUTES_BEFORE_IDLE_DEFAULT 15
  43. //
  44. // Note that the svchost registry keys to run schedule service as a part
  45. // of netsvcs is set in hivesft.inx file.
  46. //
  47. #define SCHED_SERVICE_EXE_PATH TEXT("%SystemRoot%\\System32\\svchost.exe -k netsvcs")
  48. #define SCHED_SERVICE_EXE TEXT("MSTask.exe")
  49. #define SCHED_SERVICE_DLL TEXT("MSTask.dll")
  50. #define SCHED_SERVICE_PRE_DLL TEXT("mstnt.dll")
  51. #define SCHED_SERVICE_NAME TEXT("Schedule")
  52. #define SCHED_SERVICE_GROUP TEXT("SchedulerGroup")
  53. #define MINUTESBEFOREIDLE TEXT("MinutesBeforeIdle")
  54. #define MAXLOGSIZEKB TEXT("MaxLogSizeKB")
  55. #define TASKSFOLDER TEXT("TasksFolder")
  56. #define FIRSTBOOT TEXT("FirstBoot")
  57. #define SM_SA_KEY TEXT("Software\\Microsoft\\SchedulingAgent")
  58. #define SAGE_EXE TEXT("SAGE.EXE")
  59. #define SAGE_DLL TEXT("SAGE.DLL")
  60. #define SYSAGENT_BAK TEXT("SYSAGENT.BAK")
  61. #define SYSAGENT_EXE TEXT("SYSAGENT.EXE")
  62. #define SAVED_SAGE_EXE TEXT("SAGEEXE.BAK")
  63. #define SAVED_SAGE_DLL TEXT("SAGEDLL.BAK")
  64. #define SAVED_SAGE_LINK TEXT("SAGELNK.BAK")
  65. //
  66. // Entry points from mstask.dll loaded by chicago or daytona versions of this
  67. // program. Note they are used with GetProcAddress, which always wants an
  68. // ANSI string.
  69. //
  70. #define CONVERT_SAGE_TASKS_API "ConvertSageTasksToJobs"
  71. #define CONDITIONALLY_ENABLE_API "ConditionallyEnableService"
  72. #define CONVERT_AT_TASKS_API "ConvertAtJobsToTasks"
  73. //
  74. // Function pointer types used when loading above functions from mstask.dll
  75. //
  76. typedef HRESULT (__stdcall *PSTDAPI)(void);
  77. typedef BOOL (__stdcall *PBOOLAPI)(void);
  78. typedef VOID (__stdcall *PVOIDAPI)(void);
  79. // NOTE - Debug output is turned off. To turn it on, link in smdebug.lib.
  80. #define schDebugOut(x)
  81. VOID DoPreUnsetup(void);
  82. #if defined(_CHICAGO_)
  83. VOID DoPreSetup(void);
  84. VOID DoMemphisSetup();
  85. BOOL GetOriginalShortcutLocation(LPTSTR tszPath);
  86. #else // !_CHICAGO_
  87. typedef struct _MYSIDINFO {
  88. PSID_IDENTIFIER_AUTHORITY pIdentifierAuthority;
  89. DWORD dwSubAuthority;
  90. PSID pSid;
  91. } MYSIDINFO;
  92. DWORD SetTaskFolderSecurity(LPCWSTR pwszFolderPath);
  93. DWORD AllocateAndInitializeDomainSid(
  94. PSID pDomainSid,
  95. MYSIDINFO * pDomainSidInfo);
  96. #endif // !_CHICAGO_
  97. void DoSetup(void);
  98. void DoLogon(void);
  99. void DoFirstLogon(void);
  100. BOOL IsLogonMessageSupported(void);
  101. void ErrorDialog(UINT ErrorFmtStringID, TCHAR * szRoutine, DWORD ErrorCode);
  102. HINSTANCE ghInstance = NULL;
  103. extern "C" int __cdecl _purecall(void)
  104. {
  105. return 0;
  106. }
  107. //+----------------------------------------------------------------------------
  108. //
  109. // Function: WinMainCRTStartup
  110. //
  111. // Synopsis: entry point
  112. //
  113. //-----------------------------------------------------------------------------
  114. #ifdef _CHICAGO_
  115. void
  116. WinMainCRTStartup(void)
  117. #else
  118. void _cdecl
  119. main(int argc, char ** argv)
  120. #endif // _CHICAGO_
  121. {
  122. //
  123. // Skip EXE name and find first parameter, if any
  124. //
  125. LPTSTR ptszStart;
  126. LPTSTR szArg1 = _tcstok(ptszStart = GetCommandLine(), ARG_DELIMITERS);
  127. szArg1 = _tcstok(NULL, ARG_DELIMITERS);
  128. //
  129. // Switch based on the first parameter
  130. //
  131. if (szArg1 == NULL)
  132. {
  133. ; // Do nothing
  134. #if DBG == 1
  135. MessageBox(NULL,
  136. TEXT("Missing command line arguments"),
  137. TEXT("Task Scheduler setup/init"),
  138. MB_ICONERROR | MB_OK);
  139. #endif // DBG
  140. }
  141. else if (lstrcmpi(szArg1, SCHED_LOGON_SWITCH) == 0)
  142. {
  143. DoLogon();
  144. }
  145. else if (lstrcmpi(szArg1, SCHED_FIRSTLOGON_SWITCH) == 0)
  146. {
  147. DoFirstLogon();
  148. }
  149. #if defined(_CHICAGO_)
  150. else if (lstrcmpi(szArg1, SCHED_PRESETUP_SWITCH) == 0)
  151. {
  152. DoPreSetup();
  153. }
  154. else if (lstrcmpi(szArg1, SCHED_MEMPHIS_SWITCH) == 0)
  155. {
  156. DoMemphisSetup();
  157. }
  158. #endif // defined(_CHICAGO_)
  159. else if (lstrcmpi(szArg1, SCHED_PREUNSETUP_SWITCH) == 0)
  160. {
  161. DoPreUnsetup();
  162. }
  163. else if (lstrcmpi(szArg1, SCHED_SETUP_SWITCH) == 0)
  164. {
  165. DoSetup();
  166. }
  167. #if DBG == 1
  168. else
  169. {
  170. MessageBox(NULL,
  171. TEXT("Invalid command line"),
  172. TEXT("Task Scheduler setup/init"),
  173. MB_ICONERROR | MB_OK);
  174. }
  175. #endif // DBG
  176. }
  177. #if defined(_CHICAGO_)
  178. #define MAX_KEY_LEN (ARRAY_LEN(REGSTR_PATH_APPPATHS) + MAX_PATH)
  179. //+--------------------------------------------------------------------------
  180. //
  181. // Function: GetAppPathInfo
  182. //
  183. // Synopsis: Fill [ptszAppPathDefault] with the default value and
  184. // [ptszAppPathVar] with the Path value in the
  185. // [ptszFilename] application's key under the APPPATHS regkey.
  186. //
  187. // Arguments: [ptszFilename] - application name
  188. // [ptszAppPathDefault] - if not NULL, filled with default value
  189. // [cchDefaultBuf] - size of [ptszAppPathDefault] buffer
  190. // [ptszAppPathVar] - if not NULL, filled with Path value
  191. // [cchPathVarBuf] - size of [cchPathVarBuf] buffer
  192. //
  193. // Modifies: *[ptszAppPathDefault], *[ptszAppPathVar]
  194. //
  195. // History: 11-22-1996 DavidMun Created
  196. //
  197. // Notes: Both values are optional on the registry key, so if a
  198. // requested value isn't found, it is set to "".
  199. //
  200. //---------------------------------------------------------------------------
  201. VOID
  202. GetAppPathInfo(
  203. LPCTSTR ptszFilename,
  204. LPTSTR ptszAppPathDefault,
  205. ULONG cchDefaultBuf,
  206. LPTSTR ptszAppPathVar,
  207. ULONG cchPathVarBuf)
  208. {
  209. HKEY hkey = NULL;
  210. TCHAR tszAppPathKey[MAX_KEY_LEN];
  211. //
  212. // Initialize out vars
  213. //
  214. if (ptszAppPathDefault)
  215. {
  216. ptszAppPathDefault[0] = TEXT('\0');
  217. }
  218. if (ptszAppPathVar)
  219. {
  220. ptszAppPathVar[0] = TEXT('\0');
  221. }
  222. //
  223. // Build registry key name for this app
  224. //
  225. lstrcpy(tszAppPathKey, REGSTR_PATH_APPPATHS);
  226. lstrcat(tszAppPathKey, TEXT("\\"));
  227. lstrcat(tszAppPathKey, ptszFilename);
  228. do
  229. {
  230. LRESULT lr;
  231. lr = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  232. tszAppPathKey,
  233. 0,
  234. KEY_QUERY_VALUE,
  235. &hkey);
  236. if (lr != ERROR_SUCCESS)
  237. {
  238. schDebugOut((DEB_ERROR,
  239. "GetAppPathInfo: RegOpenKeyEx lr=%u\n",
  240. GetLastError()));
  241. break;
  242. }
  243. //
  244. // If the key could be opened, attempt to read requested values.
  245. // Both are optional, so ignore errors.
  246. //
  247. DWORD cb;
  248. DWORD dwType;
  249. if (ptszAppPathDefault)
  250. {
  251. cb = cchDefaultBuf * sizeof(TCHAR);
  252. lr = RegQueryValueEx(hkey,
  253. NULL, // value name
  254. NULL, // reserved
  255. &dwType,
  256. (LPBYTE) ptszAppPathDefault,
  257. &cb);
  258. }
  259. if (ptszAppPathVar)
  260. {
  261. cb = cchPathVarBuf * sizeof(TCHAR);
  262. lr = RegQueryValueEx(hkey,
  263. TEXT("Path"), // value name
  264. NULL, // reserved
  265. &dwType,
  266. (LPBYTE) ptszAppPathVar,
  267. &cb);
  268. }
  269. } while (0);
  270. if (hkey)
  271. {
  272. RegCloseKey(hkey);
  273. }
  274. }
  275. //+--------------------------------------------------------------------------
  276. //
  277. // Function: TerminateLast
  278. //
  279. // Synopsis: Find the last occurence of [tch] in [tsz], and overwrite it
  280. // with a null.
  281. //
  282. // Arguments: [tsz] - string to search
  283. // [tch] - char to search for
  284. //
  285. // Modifies: *[tsz]
  286. //
  287. // History: 1-09-1997 DavidMun Created
  288. //
  289. // Notes: If [tch] is not found, [tsz] is not modified.
  290. //
  291. //---------------------------------------------------------------------------
  292. VOID
  293. TerminateLast(LPTSTR tsz, TCHAR tch)
  294. {
  295. LPTSTR ptszLast = NULL;
  296. LPTSTR ptsz;
  297. for (ptsz = tsz; *ptsz; ptsz = NextChar(ptsz))
  298. {
  299. if (*ptsz == tch)
  300. {
  301. ptszLast = ptsz;
  302. }
  303. }
  304. if (ptszLast)
  305. {
  306. *ptszLast = TEXT('\0');
  307. }
  308. }
  309. //+--------------------------------------------------------------------------
  310. //
  311. // Function: DoMemphisSetup
  312. //
  313. // Synopsis: If the app path for SAGE's sysagent.exe exists, replace the
  314. // sysagent.exe at that location with the one in
  315. // %windir%\system.
  316. //
  317. // History: 4-14-1997 DavidMun Created
  318. //
  319. // Notes: This is necessary for Memphis installs because their initial
  320. // setup runs in 16 bit mode. Therefore they can't invoke
  321. // this exe before the ini file runs. Therefore the inf file
  322. // for memphis can't use the CustomLDID section.
  323. //
  324. //---------------------------------------------------------------------------
  325. VOID
  326. DoMemphisSetup()
  327. {
  328. do
  329. {
  330. //
  331. // Initialize source path
  332. //
  333. UINT cchDirSize;
  334. TCHAR tszNewSysAgent[MAX_PATH + 1];
  335. cchDirSize = GetSystemDirectory(tszNewSysAgent, MAX_PATH);
  336. if (!cchDirSize || cchDirSize > MAX_PATH)
  337. {
  338. schDebugOut((DEB_ERROR,
  339. "DoMemphisSetup: GetSystemDirectory %uL\n",
  340. GetLastError()));
  341. break;
  342. }
  343. lstrcat(tszNewSysAgent, TEXT("\\") SYSAGENT_EXE);
  344. //
  345. // Initialize destination path to the location of SAGE's sysagent.exe.
  346. //
  347. // If SAGE isn't installed on this system, put our sysagent.exe
  348. // in program files\plus!, since that is created by memphis and is
  349. // the default location if a user install Plus! over Memphis.
  350. //
  351. TCHAR tszDestPath[MAX_PATH+1];
  352. GetAppPathInfo(SYSAGENT_EXE, tszDestPath, MAX_PATH + 1, NULL, 0);
  353. if (!*tszDestPath)
  354. {
  355. BOOL fOk;
  356. cchDirSize = GetWindowsDirectory(tszDestPath, MAX_PATH);
  357. if (!cchDirSize || cchDirSize > MAX_PATH)
  358. {
  359. schDebugOut((DEB_ERROR,
  360. "DoMemphisSetup: GetWindowsDirectory %uL\n",
  361. GetLastError()));
  362. break;
  363. }
  364. fOk = LoadString(ghInstance,
  365. IDS_DEFAULT_SYSAGENT_PATH,
  366. tszDestPath + 2, // preserve drive letter and colon
  367. ARRAY_LEN(tszDestPath) - 2);
  368. lstrcat(tszDestPath, TEXT("\\") SYSAGENT_EXE);
  369. }
  370. //
  371. // Copy the task scheduler version of sysagent.exe over the sage version
  372. //
  373. BOOL fOk = CopyFile(tszNewSysAgent, // pointer to name of an existing file
  374. tszDestPath, // pointer to filename to copy to
  375. FALSE); // don't fail if destination file exists
  376. //
  377. // If the old sysagent.exe was successfully copied over with the new
  378. // sysagent.exe, delete the extra new sysagent.exe in %windir%\system.
  379. //
  380. if (fOk)
  381. {
  382. DeleteFile(tszNewSysAgent);
  383. }
  384. } while (0);
  385. //
  386. // Do the rest of the setup, which is common to win95/memphis
  387. //
  388. DoSetup();
  389. }
  390. //+----------------------------------------------------------------------------
  391. //
  392. // Function: DoPreSetup
  393. //
  394. // Synopsis: Makes backups of existing sage binaries, so that they can
  395. // be restored on uninstall.
  396. //
  397. //-----------------------------------------------------------------------------
  398. VOID
  399. DoPreSetup(void)
  400. {
  401. TCHAR tszSourceFile[MAX_PATH + 1];
  402. TCHAR tszDestFile[MAX_PATH + 1];
  403. UINT ccSystemDirSize;
  404. //
  405. // See if there's an app path entry for sysagent.exe.
  406. //
  407. // If not, continue, since the plus pack may never have been installed.
  408. //
  409. // If it is found, get the application full path and truncate at the
  410. // last backslash to make a string with the full path to the
  411. // application's directory. Then add a new value with that string.
  412. //
  413. // This is necessary so the IExpress inf can create a custom LDID
  414. // (logical directory ID) pointing to the directory in which sysagent.exe
  415. // resides.
  416. //
  417. TCHAR tszSysagentInstallDir[MAX_PATH+1];
  418. GetAppPathInfo(SYSAGENT_EXE, tszSysagentInstallDir, MAX_PATH + 1, NULL, 0);
  419. if (*tszSysagentInstallDir)
  420. {
  421. GetShortPathName(tszSysagentInstallDir,
  422. tszSysagentInstallDir,
  423. MAX_PATH + 1);
  424. TerminateLast(tszSysagentInstallDir, TEXT('\\'));
  425. HKEY hkSysAgent;
  426. LONG lr = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  427. REGSTR_PATH_APPPATHS TEXT("\\") SYSAGENT_EXE,
  428. 0,
  429. KEY_SET_VALUE,
  430. &hkSysAgent);
  431. if (lr == ERROR_SUCCESS)
  432. {
  433. lr = RegSetValueEx(hkSysAgent,
  434. TEXT("InstallDir"),
  435. 0,
  436. REG_SZ,
  437. (LPBYTE) tszSysagentInstallDir,
  438. (lstrlen(tszSysagentInstallDir) + 1) *
  439. sizeof(TCHAR));
  440. RegCloseKey(hkSysAgent);
  441. if (lr != ERROR_SUCCESS)
  442. {
  443. schDebugOut((DEB_ERROR,
  444. "DoPreSetup: RegSetValueEx error %uL\n",
  445. lr));
  446. }
  447. }
  448. else
  449. {
  450. schDebugOut((DEB_ERROR,
  451. "DoPreSetup: RegOpenKeyEx error %uL\n",
  452. lr));
  453. }
  454. }
  455. //
  456. // Initialize source and destination names
  457. //
  458. if (!(ccSystemDirSize = GetSystemDirectory(tszSourceFile, MAX_PATH)) ||
  459. ccSystemDirSize > MAX_PATH)
  460. {
  461. ErrorDialog(IDS_INSTALL_FAILURE,
  462. TEXT("GetSystemDirectory"),
  463. GetLastError());
  464. return;
  465. }
  466. lstrcat(tszSourceFile, TEXT("\\"));
  467. lstrcpy(tszDestFile, tszSourceFile);
  468. //
  469. // Backup the existing sage.exe and sage.dll by copying & renaming them
  470. // from the system to the windows dir. Don't fail if the binaries don't
  471. // exist, since sage may never have been installed.
  472. //
  473. // Also fail quietly if the backup copies already exist. This keeps us
  474. // from overwriting saved SAGE binaries if user reinstalls us.
  475. //
  476. lstrcpy(&tszSourceFile[ccSystemDirSize + 1], SAGE_EXE);
  477. lstrcpy(&tszDestFile[ccSystemDirSize + 1], SAVED_SAGE_EXE);
  478. CopyFile(tszSourceFile, tszDestFile, TRUE);
  479. lstrcpy(&tszSourceFile[ccSystemDirSize + 1], SAGE_DLL);
  480. lstrcpy(&tszDestFile[ccSystemDirSize + 1], SAVED_SAGE_DLL);
  481. CopyFile(tszSourceFile, tszDestFile, TRUE);
  482. //
  483. // Back up system agent link
  484. //
  485. if (GetOriginalShortcutLocation(tszSourceFile))
  486. {
  487. lstrcpy(&tszDestFile[ccSystemDirSize + 1], SAVED_SAGE_LINK);
  488. CopyFile(tszSourceFile, tszDestFile, TRUE);
  489. }
  490. //
  491. // Backup the sysagent.exe file
  492. //
  493. if (*tszSysagentInstallDir)
  494. {
  495. lstrcat(tszSysagentInstallDir, TEXT("\\"));
  496. lstrcpy(tszSourceFile, tszSysagentInstallDir);
  497. lstrcpy(tszDestFile, tszSysagentInstallDir);
  498. lstrcat(tszSourceFile, SYSAGENT_EXE);
  499. lstrcat(tszDestFile, SYSAGENT_BAK);
  500. CopyFile(tszSourceFile, tszDestFile, TRUE);
  501. }
  502. }
  503. //+----------------------------------------------------------------------------
  504. //
  505. // Function: DoPreUnsetup
  506. //
  507. // Synopsis: Restore the System Agent start menu shortcut.
  508. //
  509. //-----------------------------------------------------------------------------
  510. VOID
  511. DoPreUnsetup(void)
  512. {
  513. UINT ccSystemDirSize;
  514. TCHAR tszSourceFile[MAX_PATH];
  515. TCHAR tszDestFile[MAX_PATH];
  516. //
  517. // Get the full path to the source file (the backup of the link)
  518. //
  519. if (!(ccSystemDirSize = GetSystemDirectory(tszSourceFile, MAX_PATH)) ||
  520. ccSystemDirSize > MAX_PATH)
  521. {
  522. schDebugOut((DEB_ERROR,
  523. "DoPreUnsetup: GetSystemDirectory error = %u\n",
  524. GetLastError()));
  525. return;
  526. }
  527. tszSourceFile[ccSystemDirSize] = TEXT('\\');
  528. lstrcpy(&tszSourceFile[ccSystemDirSize + 1], SAVED_SAGE_LINK);
  529. //
  530. // Get the full path to the destination file (the original location of the
  531. // link).
  532. //
  533. if (!GetOriginalShortcutLocation(tszDestFile))
  534. {
  535. return;
  536. }
  537. //
  538. // Now move the source file to the destination file
  539. //
  540. BOOL fOk = MoveFile(tszSourceFile, tszDestFile);
  541. if (!fOk)
  542. {
  543. schDebugOut((DEB_ERROR,
  544. "DoPreUnsetup: MoveFile(%s,%s) error = %u\n",
  545. tszSourceFile,
  546. tszDestFile,
  547. GetLastError()));
  548. }
  549. }
  550. //+---------------------------------------------------------------------------
  551. //
  552. // Function: GetOriginalShortcutLocation
  553. //
  554. // Synopsis: Fill [tszPath] with the full path to the SAGE shortcut.
  555. //
  556. // Returns: TRUE on success, FALSE on failure
  557. //
  558. // History: 11-06-96 DavidMun Created
  559. //
  560. //----------------------------------------------------------------------------
  561. BOOL
  562. GetOriginalShortcutLocation(LPTSTR tszPath)
  563. {
  564. #define LINK_EXT TEXT(".lnk")
  565. HRESULT hr;
  566. LPITEMIDLIST pidl;
  567. hr = SHGetSpecialFolderLocation(NULL, CSIDL_PROGRAMS, &pidl);
  568. if (FAILED(hr))
  569. {
  570. schDebugOut((DEB_ERROR,
  571. "GetOriginalShortcutLocation: SHGetSpecialFolderLocation hr=0x%x\n",
  572. hr));
  573. return FALSE;
  574. }
  575. BOOL fOk;
  576. fOk = SHGetPathFromIDList(pidl, tszPath);
  577. ILFree(pidl);
  578. if (!fOk)
  579. {
  580. schDebugOut((DEB_ERROR,
  581. "GetOriginalShortcutLocation: SHGetPathFromIDList failed\n"));
  582. return FALSE;
  583. }
  584. lstrcat(tszPath, TEXT("\\"));
  585. // In English IDS_SAGE_SHORTCUT_GROUP is "Accessories\\System Tools"
  586. TCHAR tszGroupName[MAX_PATH];
  587. fOk = LoadString(ghInstance,
  588. IDS_SAGE_SHORTCUT_GROUP,
  589. tszGroupName,
  590. ARRAY_LEN(tszGroupName));
  591. if (!fOk)
  592. {
  593. schDebugOut((DEB_ERROR,
  594. "GetOriginalShortcutLocation: LoadString(IDS_SAGE_SHORTCUT_GROUP) error = %u\n",
  595. GetLastError()));
  596. return FALSE;
  597. }
  598. lstrcat(tszPath, tszGroupName);
  599. lstrcat(tszPath, TEXT("\\"));
  600. TCHAR tszLinkName[MAX_PATH];
  601. fOk = LoadString(ghInstance,
  602. IDS_SAGE_SHORTCUT,
  603. tszLinkName,
  604. ARRAY_LEN(tszLinkName));
  605. if (!fOk)
  606. {
  607. schDebugOut((DEB_ERROR,
  608. "GetOriginalShortcutLocation: LoadString(IDS_SAGE_SHORTCUT) error = %u\n",
  609. GetLastError()));
  610. return FALSE;
  611. }
  612. lstrcat(tszPath, tszLinkName);
  613. lstrcat(tszPath, LINK_EXT);
  614. return TRUE;
  615. }
  616. #else // NT
  617. //+---------------------------------------------------------------------------
  618. //
  619. // Function: DoPreUnsetup
  620. //
  621. // Synopsis: Delete the admin tools (common) scheduled tasks link
  622. //
  623. // History: 11-11-96 DavidMun Created
  624. // 06-17-98 AnirudhS Link no longer created, nothing to do.
  625. //
  626. //----------------------------------------------------------------------------
  627. VOID
  628. DoPreUnsetup(void)
  629. {
  630. ;
  631. }
  632. #endif // defined(_CHICAGO_)
  633. //+----------------------------------------------------------------------------
  634. //
  635. // Function: DoSetup
  636. //
  637. // Synopsis: Performs the normal setup procedure
  638. //
  639. //-----------------------------------------------------------------------------
  640. void
  641. DoSetup(void)
  642. {
  643. #if !defined(_CHICAGO_)
  644. #define SCHED_SERVICE_DEPENDENCY L"RpcSs\0"
  645. #define SCC_AT_SVC_KEY L"System\\CurrentControlSet\\Services\\Schedule"
  646. #define TASKS_FOLDER_DEFAULT L"%SystemRoot%\\Tasks"
  647. #endif // _CHICAGO_
  648. #if defined(_CHICAGO_)
  649. TCHAR szServiceExePath[MAX_PATH + 1];
  650. #else
  651. TCHAR szTasksFolder[MAX_PATH + 1] = TEXT("");
  652. #endif // ! _CHICAGO_
  653. TCHAR tszDisplayName[50]; // "Task Scheduler"
  654. DWORD dwTmp;
  655. HKEY hKey;
  656. //
  657. // Disable hard-error popups.
  658. //
  659. SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
  660. ghInstance = GetModuleHandle(NULL);
  661. //
  662. // Load the service display name.
  663. //
  664. int cch = LoadString(ghInstance, IDS_SERVICE_DISPLAY_NAME, tszDisplayName,
  665. ARRAY_LEN(tszDisplayName));
  666. if (!(0 < cch && cch < ARRAY_LEN(tszDisplayName) - 1))
  667. {
  668. ErrorDialog(IDS_INSTALL_FAILURE,
  669. TEXT("LoadString"),
  670. GetLastError());
  671. return;
  672. }
  673. #if defined(_CHICAGO_)
  674. //
  675. // Compute the path to the service EXE.
  676. //
  677. UINT ccSystemDirSize;
  678. if (!(ccSystemDirSize = GetSystemDirectory(szServiceExePath, MAX_PATH)))
  679. {
  680. ErrorDialog(IDS_INSTALL_FAILURE,
  681. TEXT("GetSystemDirectory"),
  682. GetLastError());
  683. return;
  684. }
  685. lstrcpy(&szServiceExePath[ccSystemDirSize], TEXT("\\"));
  686. lstrcpy(&szServiceExePath[ccSystemDirSize + 1], SCHED_SERVICE_EXE);
  687. #endif
  688. //
  689. // Create/open the Scheduling Agent key in Software\Microsoft.
  690. //
  691. if (RegCreateKeyEx(HKEY_LOCAL_MACHINE,
  692. SM_SA_KEY,
  693. 0,
  694. NULL,
  695. REG_OPTION_NON_VOLATILE,
  696. KEY_ALL_ACCESS,
  697. NULL,
  698. &hKey,
  699. &dwTmp) == ERROR_SUCCESS)
  700. {
  701. // Set MinutesBeforeIdle to a default value of 15 mins.
  702. // Ignore return code.
  703. //
  704. dwTmp = MINUTES_BEFORE_IDLE_DEFAULT;
  705. RegSetValueEx(hKey,
  706. MINUTESBEFOREIDLE,
  707. 0,
  708. REG_DWORD,
  709. (CONST BYTE *)&dwTmp,
  710. sizeof(dwTmp));
  711. // Set MaxLogSizeKB to 32K or 0x7FFF.
  712. // Ignore return code.
  713. //
  714. dwTmp = MAX_LOG_SIZE_DEFAULT;
  715. RegSetValueEx(hKey,
  716. MAXLOGSIZEKB,
  717. 0,
  718. REG_DWORD,
  719. (CONST BYTE *)&dwTmp,
  720. sizeof(dwTmp));
  721. #if !defined(_CHICAGO_)
  722. // Read the tasks folder location. The .INF should've set this.
  723. // If not, default.
  724. //
  725. dwTmp = MAX_PATH * sizeof(TCHAR);
  726. if (RegQueryValueEx(hKey,
  727. TASKSFOLDER,
  728. NULL,
  729. NULL,
  730. (LPBYTE)szTasksFolder,
  731. &dwTmp) != ERROR_SUCCESS ||
  732. szTasksFolder[0] == TEXT('\0'))
  733. {
  734. lstrcpy(szTasksFolder, TASKS_FOLDER_DEFAULT);
  735. }
  736. // Set FirstBoot to non-zero.
  737. // Ignore return code.
  738. //
  739. dwTmp = 1;
  740. RegSetValueEx(hKey,
  741. FIRSTBOOT,
  742. 0,
  743. REG_DWORD,
  744. (CONST BYTE *)&dwTmp,
  745. sizeof(dwTmp));
  746. #endif // ! _CHICAGO_
  747. RegCloseKey(hKey);
  748. }
  749. #if !defined(_CHICAGO_)
  750. //
  751. // Set the right permissions on the job folder.
  752. // The default permissions allow anyone to delete any job, which we
  753. // don't want.
  754. //
  755. {
  756. TCHAR szTaskFolderPath[MAX_PATH + 1];
  757. DWORD cch = ExpandEnvironmentStrings(szTasksFolder,
  758. szTaskFolderPath,
  759. ARRAY_LEN(szTaskFolderPath));
  760. if (cch == 0 || cch > ARRAY_LEN(szTaskFolderPath))
  761. {
  762. //
  763. // The job folder path is too long.
  764. //
  765. ErrorDialog(IDS_INSTALL_FAILURE,
  766. TEXT("ExpandEnvironmentStrings"),
  767. cch ? ERROR_BUFFER_OVERFLOW : GetLastError());
  768. return;
  769. }
  770. DWORD dwError = SetTaskFolderSecurity(szTaskFolderPath);
  771. if (dwError != ERROR_SUCCESS)
  772. {
  773. ErrorDialog(IDS_INSTALL_FAILURE,
  774. TEXT("SetTaskFolderSecurity"),
  775. dwError);
  776. return;
  777. }
  778. }
  779. #endif // ! _CHICAGO_
  780. HINSTANCE hinstMSTask;
  781. #if defined(_CHICAGO_)
  782. hinstMSTask = LoadLibrary(SCHED_SERVICE_DLL);
  783. #else
  784. hinstMSTask = LoadLibrary(SCHED_SERVICE_PRE_DLL);
  785. //
  786. // If we're being installed as part of DS setup then we're not using
  787. // iexpress, so dll name is SCHED_SERVICE_DLL.
  788. //
  789. if (!hinstMSTask)
  790. {
  791. hinstMSTask = LoadLibrary(SCHED_SERVICE_DLL);
  792. }
  793. #endif // defined(_CHICAGO_)
  794. if (!hinstMSTask)
  795. {
  796. ErrorDialog(IDS_INSTALL_FAILURE,
  797. SCHED_SERVICE_DLL,
  798. GetLastError());
  799. return;
  800. }
  801. #if defined(_CHICAGO_)
  802. PSTDAPI pfnConvertLegacyJobsToTasks = (PSTDAPI)
  803. GetProcAddress(hinstMSTask, CONVERT_SAGE_TASKS_API);
  804. #else
  805. PVOIDAPI pfnConvertLegacyJobsToTasks = (PVOIDAPI)
  806. GetProcAddress(hinstMSTask, CONVERT_AT_TASKS_API);
  807. #endif
  808. PBOOLAPI pfnConditionallyEnableService = (PBOOLAPI)
  809. GetProcAddress(hinstMSTask, CONDITIONALLY_ENABLE_API);
  810. if (!pfnConvertLegacyJobsToTasks || !pfnConditionallyEnableService)
  811. {
  812. ErrorDialog(IDS_INSTALL_FAILURE,
  813. TEXT("GetProcAddress"),
  814. GetLastError());
  815. return;
  816. }
  817. pfnConvertLegacyJobsToTasks();
  818. //
  819. // ConditionallyEnableService *MUST* be after ConvertSageTasksToJobs
  820. // or ConvertAtJobsToTasks!
  821. //
  822. #if defined(_CHICAGO_)
  823. //
  824. // If and only if there are jobs to run, enable the service and create
  825. // the "Run = mstinit.exe /firstlogon" registry entry.
  826. //
  827. BOOL fServiceEnabled = pfnConditionallyEnableService();
  828. if (fServiceEnabled)
  829. {
  830. //
  831. // Start the service, if not already running.
  832. //
  833. HWND hwnd = FindWindow(SCHED_SERVICE_NAME, tszDisplayName);
  834. if (hwnd == NULL)
  835. {
  836. //
  837. // Create a process to open the log.
  838. //
  839. STARTUPINFO si;
  840. PROCESS_INFORMATION pi;
  841. ZeroMemory(&si, sizeof(si));
  842. si.cb = sizeof (STARTUPINFO);
  843. BOOL fRet = CreateProcess(szServiceExePath,
  844. NULL,
  845. NULL,
  846. NULL,
  847. FALSE,
  848. CREATE_NEW_CONSOLE |
  849. CREATE_NEW_PROCESS_GROUP,
  850. NULL,
  851. NULL,
  852. &si,
  853. &pi);
  854. if (fRet == 0)
  855. {
  856. ErrorDialog(IDS_START_FAILURE,
  857. TEXT("CreateProcess"),
  858. GetLastError());
  859. return;
  860. }
  861. }
  862. }
  863. #else // NT
  864. //
  865. // Install the Win32 service.
  866. //
  867. SC_HANDLE hSCMgr = OpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE);
  868. if (hSCMgr == NULL)
  869. {
  870. //
  871. // Yow, we're hosed.
  872. //
  873. ErrorDialog(IDS_INSTALL_FAILURE,
  874. TEXT("OpenSCManager"),
  875. GetLastError());
  876. return;
  877. }
  878. //
  879. // Is the service already installed? If so, change its parameters;
  880. // otherwise, create it.
  881. //
  882. SC_HANDLE hSvc = OpenService(hSCMgr,
  883. SCHED_SERVICE_NAME,
  884. SERVICE_CHANGE_CONFIG);
  885. if (hSvc == NULL)
  886. {
  887. hSvc = CreateService(hSCMgr,
  888. SCHED_SERVICE_NAME,
  889. tszDisplayName,
  890. SERVICE_CHANGE_CONFIG,
  891. SERVICE_WIN32_SHARE_PROCESS |
  892. SERVICE_INTERACTIVE_PROCESS,
  893. SERVICE_AUTO_START,
  894. SERVICE_ERROR_NORMAL,
  895. SCHED_SERVICE_EXE_PATH,
  896. SCHED_SERVICE_GROUP,
  897. NULL,
  898. SCHED_SERVICE_DEPENDENCY,
  899. NULL,
  900. NULL);
  901. if (hSvc == NULL)
  902. {
  903. ErrorDialog(IDS_INSTALL_FAILURE,
  904. TEXT("CreateService"),
  905. GetLastError());
  906. CloseServiceHandle(hSCMgr);
  907. return;
  908. }
  909. }
  910. else
  911. {
  912. //
  913. // This path will be followed when we upgrade the At service
  914. // to the Scheduling Agent. The service name will remain the
  915. // same, but the display name will be set to the new display
  916. // name (the At service had no display name) and the image path
  917. // will be changed to point to the new exe.
  918. // (The old binary will be left on disk in order to make it easy
  919. // to revert to it, in case of compatibility problems.)
  920. //
  921. if (!ChangeServiceConfig(
  922. hSvc, // hService
  923. SERVICE_WIN32_SHARE_PROCESS |
  924. SERVICE_INTERACTIVE_PROCESS, // dwServiceType
  925. SERVICE_AUTO_START, // dwStartType
  926. SERVICE_ERROR_NORMAL, // dwErrorControl
  927. SCHED_SERVICE_EXE_PATH, // lpBinaryPathName
  928. SCHED_SERVICE_GROUP, // lpLoadOrderGroup
  929. NULL, // lpdwTagId
  930. SCHED_SERVICE_DEPENDENCY, // lpDependencies
  931. L".\\LocalSystem", // lpServiceStartName
  932. L"", // lpPassword
  933. tszDisplayName // lpDisplayName
  934. ))
  935. {
  936. ErrorDialog(IDS_INSTALL_FAILURE,
  937. TEXT("ChangeServiceConfig"),
  938. GetLastError());
  939. CloseServiceHandle(hSvc);
  940. CloseServiceHandle(hSCMgr);
  941. return;
  942. }
  943. }
  944. CloseServiceHandle(hSvc);
  945. CloseServiceHandle(hSCMgr);
  946. //
  947. // If and only if there are jobs to run, enable the service and create
  948. // the "Run = mstinit.exe /firstlogon" registry entry.
  949. //
  950. pfnConditionallyEnableService();
  951. #endif // _CHICAGO_
  952. }
  953. //+----------------------------------------------------------------------------
  954. //
  955. // Function: DoLogon
  956. //
  957. // Synopsis: Sends a message to the service indicating that a user has
  958. // logged on.
  959. //
  960. //-----------------------------------------------------------------------------
  961. void
  962. DoLogon(void)
  963. {
  964. //
  965. // This instance has been invoked by the Run key of the registry to
  966. // signal the running service that a user has logged on.
  967. //
  968. #ifdef _CHICAGO_
  969. schDebugOut((DEB_ITRACE, "Sending user log on message.\n"));
  970. HWND hwndSvc = FindWindow(SCHED_CLASS, SCHED_TITLE);
  971. if (hwndSvc == NULL)
  972. {
  973. schDebugOut((DEB_ITRACE,
  974. "FindWindow: service window not found (%d)\n",
  975. GetLastError()));
  976. }
  977. else
  978. {
  979. PostMessage(hwndSvc, WM_SCHED_WIN9X_USER_LOGON, 0, 0);
  980. }
  981. #else // NT
  982. schDebugOut((DEB_ITRACE,
  983. "Sending user log on notification...........\n"));
  984. SC_HANDLE hSC = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
  985. if (hSC == NULL)
  986. {
  987. schDebugOut((DEB_ERROR,
  988. "DoLogon: OpenSCManager error = %uL\n",
  989. GetLastError()));
  990. return;
  991. }
  992. SC_HANDLE hSvc = OpenService(hSC, SCHED_SERVICE_NAME,
  993. SERVICE_USER_DEFINED_CONTROL);
  994. if (hSvc == NULL)
  995. {
  996. schDebugOut((DEB_ERROR,
  997. "DoLogon: OpenService(%s) error = %uL\n",
  998. SCHED_SERVICE_NAME,
  999. GetLastError()));
  1000. CloseServiceHandle(hSC);
  1001. return;
  1002. }
  1003. BOOL fSucceeded;
  1004. const int NOTIFY_RETRIES = 20;
  1005. const DWORD NOTIFY_SLEEP = 4000;
  1006. //
  1007. // Use a retry loop to notify the service. This is done
  1008. // because, if the user logs in quickly, the service may not
  1009. // be started when the shell runs this instance.
  1010. //
  1011. for (int i = 1; ; i++)
  1012. {
  1013. SERVICE_STATUS Status;
  1014. fSucceeded = ControlService(hSvc,
  1015. SERVICE_CONTROL_USER_LOGON,
  1016. &Status);
  1017. if (fSucceeded)
  1018. {
  1019. break;
  1020. }
  1021. if (i >= NOTIFY_RETRIES)
  1022. {
  1023. SetLastError(0); // There's no good error code
  1024. break;
  1025. }
  1026. schDebugOut((DEB_ITRACE,
  1027. "Service notification failed, waiting to "
  1028. "send it again...\n"));
  1029. Sleep(NOTIFY_SLEEP);
  1030. }
  1031. CloseServiceHandle(hSvc);
  1032. CloseServiceHandle(hSC);
  1033. #endif // _CHICAGO_
  1034. }
  1035. //+----------------------------------------------------------------------------
  1036. //
  1037. // Function: DoFirstLogon
  1038. //
  1039. // Synopsis: Checks whether the shell supports the tray startup notify
  1040. // message. If it does, simply removes the "Run = " value from
  1041. // the registry, so that this will not run at future logons.
  1042. // If it doesn't, changes the "Run = " value's command line
  1043. // parameter from "/FirstLogon" to "/Logon", and then calls
  1044. // DoLogon.
  1045. //
  1046. //-----------------------------------------------------------------------------
  1047. void
  1048. DoFirstLogon(void)
  1049. {
  1050. // CODEWORK: Use winlogon for logon notifies on NT?
  1051. BOOL bLogonMessageSupported = IsLogonMessageSupported();
  1052. HKEY hRunKey;
  1053. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  1054. REGSTR_PATH_RUN,
  1055. 0,
  1056. KEY_SET_VALUE,
  1057. &hRunKey) == ERROR_SUCCESS)
  1058. {
  1059. if (bLogonMessageSupported)
  1060. {
  1061. RegDeleteValue(hRunKey, SCH_RUN_VALUE);
  1062. }
  1063. else
  1064. {
  1065. #define NewValue SCHED_SETUP_APP_NAME TEXT(" ") SCHED_LOGON_SWITCH
  1066. RegSetValueEx(hRunKey,
  1067. SCH_RUN_VALUE,
  1068. 0,
  1069. REG_SZ,
  1070. (CONST BYTE *) (NewValue),
  1071. sizeof(NewValue));
  1072. }
  1073. RegCloseKey(hRunKey);
  1074. }
  1075. // If RegOpenKeyEx fails, we just have to retry at the next logon.
  1076. if (! bLogonMessageSupported)
  1077. {
  1078. DoLogon();
  1079. }
  1080. }
  1081. //+---------------------------------------------------------------------------
  1082. //
  1083. // Function: IsLogonMessageSupported
  1084. //
  1085. // Synopsis: Determines whether the currently installed shell version
  1086. // broadcasts the "TaskbarCreated" message.
  1087. //
  1088. // Arguments: None.
  1089. //
  1090. // Returns: TRUE - the logon message is supported.
  1091. // FALSE - it is not supported; or, this cannot be determined.
  1092. //
  1093. // Notes: The "TaskbarCreated" message tells the service that (1) a
  1094. // user has logged on, and (2) it's time to create our tray icon.
  1095. //
  1096. //----------------------------------------------------------------------------
  1097. BOOL
  1098. IsLogonMessageSupported()
  1099. {
  1100. // CODEWORK Use GetFileVersionInfo instead, once the version numbers are fixed.
  1101. HINSTANCE hLib = LoadLibrary(TEXT("SHELL32.DLL"));
  1102. if (hLib == NULL)
  1103. {
  1104. return FALSE;
  1105. }
  1106. FARPROC VersionProc = GetProcAddress(hLib, "DllGetVersion");
  1107. FreeLibrary(hLib);
  1108. //
  1109. // Versions of shell32.dll that export DllGetVersion support the logon
  1110. // message.
  1111. //
  1112. return (VersionProc != NULL);
  1113. }
  1114. //+----------------------------------------------------------------------------
  1115. //
  1116. // Function: ErrorDialog
  1117. //
  1118. // Synopsis: Displays an error message.
  1119. //
  1120. //-----------------------------------------------------------------------------
  1121. void
  1122. ErrorDialog(UINT ErrorFmtStringID, TCHAR * szRoutine, DWORD ErrorCode)
  1123. {
  1124. #define ERROR_BUFFER_SIZE (MAX_PATH * 2)
  1125. TCHAR szErrorFmt[MAX_PATH + 1] = TEXT("");
  1126. TCHAR szError[ERROR_BUFFER_SIZE + 1];
  1127. TCHAR * pszError = szError;
  1128. LoadString(ghInstance, ErrorFmtStringID, szErrorFmt, MAX_PATH);
  1129. if (*szErrorFmt)
  1130. {
  1131. wsprintf(szError, szErrorFmt, szRoutine, ErrorCode);
  1132. }
  1133. else
  1134. {
  1135. //
  1136. // Not a localizable string, but done just in case LoadString
  1137. // should fail for some reason.
  1138. //
  1139. lstrcpy(szErrorFmt,
  1140. TEXT("Error installing Task Scheduler; error = 0x%x"));
  1141. wsprintf(szError, szErrorFmt, ErrorCode);
  1142. }
  1143. MessageBox(NULL, szError, NULL, MB_ICONSTOP | MB_OK);
  1144. }
  1145. #if !defined(_CHICAGO_)
  1146. //+---------------------------------------------------------------------------
  1147. //
  1148. // Function: SetTaskFolderSecurity
  1149. //
  1150. // Synopsis: Grant the following permissions to the task folder:
  1151. //
  1152. // LocalSystem All Access.
  1153. // Domain Administrators All Access.
  1154. // World RWX Access (no permission to delete
  1155. // child files).
  1156. //
  1157. // Arguments: [pwszFolderPath] -- Task folder path.
  1158. //
  1159. // Notes: None.
  1160. //
  1161. //----------------------------------------------------------------------------
  1162. DWORD
  1163. SetTaskFolderSecurity(LPCWSTR pwszFolderPath)
  1164. {
  1165. #define BASE_SID_COUNT 4
  1166. #define DOMAIN_SID_COUNT 1
  1167. #define TASK_ACE_COUNT 4
  1168. PSECURITY_DESCRIPTOR pSecurityDescriptor = NULL;
  1169. DWORD Status = ERROR_SUCCESS;
  1170. DWORD i;
  1171. //
  1172. // Build the SIDs that will go in the security descriptor.
  1173. //
  1174. SID_IDENTIFIER_AUTHORITY NtAuth = SECURITY_NT_AUTHORITY;
  1175. SID_IDENTIFIER_AUTHORITY CreatorAuth = SECURITY_CREATOR_SID_AUTHORITY;
  1176. MYSIDINFO rgBaseSidInfo[BASE_SID_COUNT] = {
  1177. { &NtAuth, // Local System.
  1178. SECURITY_LOCAL_SYSTEM_RID,
  1179. NULL },
  1180. { &NtAuth, // Built in domain. (Used for
  1181. SECURITY_BUILTIN_DOMAIN_RID, // domain admins SID.)
  1182. NULL },
  1183. { &NtAuth, // Authenticated user.
  1184. SECURITY_AUTHENTICATED_USER_RID,
  1185. NULL },
  1186. { &CreatorAuth, // Creator.
  1187. SECURITY_CREATOR_OWNER_RID,
  1188. NULL },
  1189. };
  1190. MYSIDINFO rgDomainSidInfo[DOMAIN_SID_COUNT] = {
  1191. { NULL, // Domain administrators.
  1192. DOMAIN_ALIAS_RID_ADMINS,
  1193. NULL }
  1194. };
  1195. //
  1196. // Create the base SIDs.
  1197. //
  1198. for (i = 0; i < BASE_SID_COUNT; i++)
  1199. {
  1200. if (!AllocateAndInitializeSid(rgBaseSidInfo[i].pIdentifierAuthority,
  1201. 1,
  1202. rgBaseSidInfo[i].dwSubAuthority,
  1203. 0, 0, 0, 0, 0, 0, 0,
  1204. &rgBaseSidInfo[i].pSid))
  1205. {
  1206. Status = GetLastError();
  1207. break;
  1208. }
  1209. }
  1210. if (Status == ERROR_SUCCESS)
  1211. {
  1212. //
  1213. // Create the domain SIDs.
  1214. //
  1215. for (i = 0; i < DOMAIN_SID_COUNT; i++)
  1216. {
  1217. Status = AllocateAndInitializeDomainSid(rgBaseSidInfo[1].pSid,
  1218. &rgDomainSidInfo[i]);
  1219. if (Status != ERROR_SUCCESS)
  1220. {
  1221. break;
  1222. }
  1223. }
  1224. }
  1225. //
  1226. // Create the security descriptor.
  1227. //
  1228. PACCESS_ALLOWED_ACE rgAce[TASK_ACE_COUNT] = {
  1229. NULL, NULL, NULL // Supply this to CreateSD so we
  1230. }; // don't have to allocate memory.
  1231. MYACE rgMyAce[TASK_ACE_COUNT] = {
  1232. { FILE_ALL_ACCESS,
  1233. OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE,
  1234. rgBaseSidInfo[0].pSid }, // Local System
  1235. { FILE_ALL_ACCESS,
  1236. OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE,
  1237. rgDomainSidInfo[0].pSid }, // Domain admins
  1238. { FILE_GENERIC_READ | FILE_GENERIC_EXECUTE | FILE_WRITE_DATA,
  1239. 0,
  1240. rgBaseSidInfo[2].pSid }, // Authenticated user
  1241. { FILE_ALL_ACCESS,
  1242. OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE,
  1243. rgBaseSidInfo[3].pSid } // Creator
  1244. };
  1245. if (Status != ERROR_SUCCESS)
  1246. {
  1247. goto CleanExit;
  1248. }
  1249. if ((pSecurityDescriptor = CreateSecurityDescriptor(TASK_ACE_COUNT,
  1250. rgMyAce,
  1251. rgAce,
  1252. &Status)) == NULL)
  1253. {
  1254. goto CleanExit;
  1255. }
  1256. //
  1257. // Finally, set permissions.
  1258. //
  1259. if (!SetFileSecurity(pwszFolderPath,
  1260. DACL_SECURITY_INFORMATION,
  1261. pSecurityDescriptor))
  1262. {
  1263. Status = GetLastError();
  1264. goto CleanExit;
  1265. }
  1266. CleanExit:
  1267. for (i = 0; i < BASE_SID_COUNT; i++)
  1268. {
  1269. if (rgBaseSidInfo[i].pSid != NULL)
  1270. {
  1271. FreeSid(rgBaseSidInfo[i].pSid);
  1272. }
  1273. }
  1274. for (i = 0; i < DOMAIN_SID_COUNT; i++)
  1275. {
  1276. LocalFree(rgDomainSidInfo[i].pSid);
  1277. }
  1278. if (pSecurityDescriptor != NULL)
  1279. {
  1280. DeleteSecurityDescriptor(pSecurityDescriptor);
  1281. }
  1282. return(Status);
  1283. }
  1284. //+---------------------------------------------------------------------------
  1285. //
  1286. // Function: AllocateAndInitializeDomainSid
  1287. //
  1288. // Synopsis:
  1289. //
  1290. // Arguments: [pDomainSid] --
  1291. // [pDomainSidInfo] --
  1292. //
  1293. // Notes: None.
  1294. //
  1295. //----------------------------------------------------------------------------
  1296. DWORD
  1297. AllocateAndInitializeDomainSid(
  1298. PSID pDomainSid,
  1299. MYSIDINFO * pDomainSidInfo)
  1300. {
  1301. UCHAR DomainIdSubAuthorityCount;
  1302. DWORD SidLength;
  1303. //
  1304. // Allocate a Sid which has one more sub-authority than the domain ID.
  1305. //
  1306. DomainIdSubAuthorityCount = *(GetSidSubAuthorityCount(pDomainSid));
  1307. SidLength = GetSidLengthRequired(DomainIdSubAuthorityCount + 1);
  1308. pDomainSidInfo->pSid = (PSID) LocalAlloc(0, SidLength);
  1309. if (pDomainSidInfo->pSid == NULL)
  1310. {
  1311. return(ERROR_NOT_ENOUGH_MEMORY);
  1312. }
  1313. //
  1314. // Initialize the new SID to have the same initial value as the
  1315. // domain ID.
  1316. //
  1317. if (!CopySid(SidLength, pDomainSidInfo->pSid, pDomainSid))
  1318. {
  1319. LocalFree(pDomainSidInfo->pSid);
  1320. pDomainSidInfo->pSid = NULL;
  1321. return(GetLastError());
  1322. }
  1323. //
  1324. // Adjust the sub-authority count and add the relative Id unique
  1325. // to the newly allocated SID
  1326. //
  1327. (*(GetSidSubAuthorityCount(pDomainSidInfo->pSid)))++;
  1328. *(GetSidSubAuthority(pDomainSidInfo->pSid,
  1329. DomainIdSubAuthorityCount)) =
  1330. pDomainSidInfo->dwSubAuthority;
  1331. return(ERROR_SUCCESS);
  1332. }
  1333. #endif // !_CHICAGO_