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.

3147 lines
86 KiB

  1. /****************************** Module Header ******************************\
  2. * Module Name: userinit.c
  3. *
  4. * Copyright (c) 1991, Microsoft Corporation
  5. *
  6. * Userinit main module
  7. *
  8. * Userinit is an app executed by winlogon at user logon.
  9. * It executes in the security context of the user and on the user desktop.
  10. * Its purpose is to complete any user initialization that may take an
  11. * indeterminate time. e.g. code that interacts with the user.
  12. * This process may be terminated at any time if a shutdown is initiated
  13. * or if the user logs off by some other means.
  14. *
  15. * History:
  16. * 20-Aug-92 Davidc Created.
  17. \***************************************************************************/
  18. #include "userinit.h"
  19. #include "winuserp.h"
  20. #include <mpr.h>
  21. #include <winnetp.h>
  22. #include <winspool.h>
  23. #include <winsprlp.h>
  24. #include "msgalias.h"
  25. #include "stringid.h"
  26. #include "strings.h"
  27. #include <stdio.h>
  28. #include <string.h>
  29. #include <math.h>
  30. #include <stdlib.h>
  31. #include <shellapi.h>
  32. #include <regapi.h>
  33. #include <dsgetdc.h>
  34. #include <lm.h>
  35. #include "helpmsg.h" // for HelpMessageBox
  36. #include <userenv.h>
  37. #include <userenvp.h>
  38. /****************************************************************************
  39. IsTSAppCompatOn()
  40. Purpose:
  41. Checks if TS application compatibility is enabled.
  42. returns TRUE if enabled, FALSE - if not enabled or on case of error.
  43. Comments:
  44. This function goes to the registry only once.
  45. All other times it just returnes the value.
  46. ****************************************************************************/
  47. BOOL IsTSAppCompatOn();
  48. //
  49. // Define this to enable verbose output for this module
  50. //
  51. // #define DEBUG_USERINIT
  52. #ifdef DEBUG_USERINIT
  53. #define VerbosePrint(s) UIPrint(s)
  54. #else
  55. #define VerbosePrint(s)
  56. #endif
  57. //
  58. // Define this to enable timing of userinit
  59. //
  60. //#define LOGGING
  61. #ifdef LOGGING
  62. void _WriteLog(LPCTSTR LogString);
  63. #define WriteLog(s) _WriteLog(s)
  64. #else
  65. #define WriteLog(s)
  66. #endif
  67. //
  68. // Define the environment variable names used to pass the logon
  69. // server and script name from winlogon
  70. //
  71. #define LOGON_SERVER_VARIABLE TEXT("UserInitLogonServer")
  72. #define LOGON_SCRIPT_VARIABLE TEXT("UserInitLogonScript")
  73. #define MPR_LOGON_SCRIPT_VARIABLE TEXT("UserInitMprLogonScript")
  74. #define GPO_SCRIPT_TYPE_VARIABLE TEXT("UserInitGPOScriptType")
  75. #define OPTIMIZED_LOGON_VARIABLE TEXT("UserInitOptimizedLogon")
  76. #define EVENT_SOURCE_NAME TEXT("UserInit")
  77. #define USERDOMAIN_VARIABLE TEXT("USERDOMAIN")
  78. #define UNC_LOGON_SERVER_VARIABLE TEXT("LOGONSERVER")
  79. #define AUTOENROLL_VARIABLE TEXT("UserInitAutoEnroll")
  80. #define AUTOENROLL_NONEXCLUSIVE TEXT("1")
  81. #define AUTOENROLL_EXCLUSIVE TEXT("2")
  82. #define AUTOENROLLMODE_VARIABLE TEXT("UserInitAutoEnrollMode")
  83. #define AUTOENROLL_STARTUP TEXT("1")
  84. #define AUTOENROLL_WAKEUP TEXT("2")
  85. #define SCRIPT_ZONE_CHECK_VARIABLE TEXT("SEE_MASK_NOZONECHECKS")
  86. #define SCRIPT_ZONE_CHECK_DISABLE TEXT("1")
  87. //
  88. // Define path separator
  89. //
  90. #define PATH_SEPARATOR TEXT("\\")
  91. //
  92. // Define filename extension separator
  93. //
  94. #define EXTENSION_SEPARATOR_CHAR TEXT('.')
  95. //
  96. // Define server name prefix
  97. //
  98. #define SERVER_PREFIX TEXT("\\\\")
  99. //
  100. // Define Logon script paths.
  101. //
  102. #define SERVER_SCRIPT_PATH TEXT("\\NETLOGON")
  103. #define LOCAL_SCRIPT_PATH TEXT("\\repl\\import\\scripts")
  104. #define WINLOGON_KEY TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon")
  105. #define WINLOGON_POLICY_KEY TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System")
  106. #define GPO_SCRIPTS_KEY TEXT("Software\\Policies\\Microsoft\\Windows\\System\\Scripts")
  107. #define SYNC_LOGON_SCRIPT TEXT("RunLogonScriptSync")
  108. #define SYNC_STARTUP_SCRIPT TEXT("RunStartupScriptSync")
  109. #define GRPCONV_REG_VALUE_NAME TEXT("RunGrpConv")
  110. #define CTFMON_KEY TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Run")
  111. #define REG_CTFMON TEXT("ctfmon.exe")
  112. //
  113. // We cache user preference to run logon scripts synchronously
  114. // in the machine hive so it can be checked to determine if we
  115. // can do cached logon without having to load the user's hive.
  116. //
  117. #define PROFILE_LIST_PATH L"Software\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList"
  118. TCHAR g_szGrpConvExe[] = TEXT("grpconv.exe -p");
  119. //
  120. // Define extensions that should be added to scripts without extensions
  121. // when we go search for them. Basically this list includes those extensions
  122. // that CreateProcess handles when they are present in the executable file
  123. // name but must be provided by the caller (us)
  124. // We search for a script file with these extensions in this order and
  125. // execute the first one we find.
  126. //
  127. static LPTSTR ScriptExtensions[] = { TEXT(".bat"), TEXT(".cmd") };
  128. //
  129. // Name of registry key and value to check for temp page file.
  130. //
  131. TCHAR szMemMan[] =
  132. TEXT("System\\CurrentControlSet\\Control\\Session Manager\\Memory Management");
  133. TCHAR szNoPageFile[] = TEXT("TempPageFile");
  134. //
  135. // Handle to a thread that may be created to deal with autoenrollment goo.
  136. // If this is non-null, we will wait on this thread to complete before
  137. // terminating the process.
  138. //
  139. HANDLE AutoEnrollThread ;
  140. //
  141. // Timeout in miliseconds to wait for AddMessageAlias to complete
  142. //
  143. #define TIMEOUT_VALUE (5L * 60L * 1000L)
  144. #define MAX_STRING_BYTES 512
  145. BOOL SetupHotKeyForKeyboardLayout ();
  146. LPTSTR
  147. AllocAndGetEnvironmentVariable(
  148. LPTSTR lpName
  149. );
  150. BOOL
  151. RunScriptHidden(HKEY hKeyRoot, LPTSTR lpValue, BOOL bDefault);
  152. BOOL
  153. RunLogonScriptSync(VOID);
  154. BOOL
  155. RunStartupScriptSync(VOID);
  156. BOOL
  157. UpdateUserEnvironment(VOID);
  158. LPWSTR
  159. GetSidString(HANDLE UserToken);
  160. VOID
  161. DeleteSidString(LPWSTR SidString);
  162. VOID
  163. UpdateUserSyncLogonScriptsCache(BOOL bSync);
  164. VOID
  165. NewLogonNotify(VOID);
  166. BOOL
  167. RunGPOScripts(
  168. LPTSTR lpGPOScriptType
  169. );
  170. void
  171. PathUnquoteSpaces(LPTSTR lpsz);
  172. BOOLEAN
  173. RegCheckCtfmon(PWCHAR szCtfmon, DWORD cbSize);
  174. BOOL
  175. PrependToPath(
  176. IN LPTSTR lpLogonPath,
  177. OUT LPTSTR *lpOldPath
  178. );
  179. typedef BOOL (*PFNSHELLEXECUTEEX)(LPSHELLEXECUTEINFO lpExecInfo);
  180. PFNSHELLEXECUTEEX g_pfnShellExecuteEx=NULL;
  181. // If a path is contained in quotes then remove them.
  182. void PathUnquoteSpaces(LPTSTR lpsz)
  183. {
  184. int cch;
  185. cch = lstrlen(lpsz);
  186. // Are the first and last chars quotes?
  187. if (lpsz[0] == TEXT('"') && lpsz[cch-1] == TEXT('"'))
  188. {
  189. // Yep, remove them.
  190. lpsz[cch-1] = 0;
  191. MoveMemory(lpsz, lpsz+1, (cch-1) * sizeof(TCHAR));
  192. }
  193. }
  194. // Following function determines if the machine is a Pro or Personal machine
  195. BOOL IsPerOrProTerminalServer()
  196. {
  197. OSVERSIONINFOEX osVersion = {0};
  198. osVersion.dwOSVersionInfoSize = sizeof(osVersion);
  199. return(GetVersionEx((OSVERSIONINFO*)&osVersion) &&
  200. (osVersion.wProductType == VER_NT_WORKSTATION) &&
  201. (osVersion.wSuiteMask & VER_SUITE_SINGLEUSERTS));
  202. }
  203. //
  204. // The 3 functions below are duplicated in gptext as well
  205. // for running GPO scripts
  206. //
  207. /***************************************************************************\
  208. * AllocAndGetEnvironmentVariable
  209. *
  210. * Version of GetEnvironmentVariable that allocates the return buffer.
  211. *
  212. * Returns pointer to environment variable or NULL on failure
  213. *
  214. * The returned buffer should be free using Free()
  215. *
  216. * History:
  217. * 09-Dec-92 Davidc Created
  218. *
  219. \***************************************************************************/
  220. LPTSTR
  221. AllocAndGetEnvironmentVariable(
  222. LPTSTR lpName
  223. )
  224. {
  225. LPTSTR Buffer;
  226. DWORD LengthRequired;
  227. DWORD LengthUsed;
  228. DWORD BytesRequired;
  229. //
  230. // Go search for the variable and find its length
  231. //
  232. LengthRequired = GetEnvironmentVariable(lpName, NULL, 0);
  233. if (LengthRequired == 0) {
  234. VerbosePrint(("Environment variable <%S> not found, error = %d", lpName, GetLastError()));
  235. return(NULL);
  236. }
  237. //
  238. // Allocate a buffer to hold the variable
  239. //
  240. BytesRequired = LengthRequired * sizeof(TCHAR);
  241. Buffer = (LPTSTR) Alloc(BytesRequired);
  242. if (Buffer == NULL) {
  243. VerbosePrint(("Failed to allocate %d bytes for environment variable", BytesRequired));
  244. return(NULL);
  245. }
  246. //
  247. // Go get the variable and pass a buffer this time
  248. //
  249. LengthUsed = GetEnvironmentVariable(lpName, Buffer, LengthRequired);
  250. if (LengthUsed == 0) {
  251. VerbosePrint(("Environment variable <%S> not found (should have found it), error = %d", lpName, GetLastError()));
  252. Free(Buffer);
  253. return(NULL);
  254. }
  255. if (LengthUsed != LengthRequired - 1) {
  256. VerbosePrint(("Unexpected result from GetEnvironmentVariable. Length passed = %d, length used = %d (expected %d)", LengthRequired, LengthUsed, LengthRequired - 1));
  257. Free(Buffer);
  258. return(NULL);
  259. }
  260. return(Buffer);
  261. }
  262. //
  263. // Directory separator in environment strings
  264. //
  265. #define DIRECTORY_SEPARATOR TEXT(";")
  266. BOOL
  267. PrependToPath(
  268. IN LPTSTR lpLogonPath,
  269. OUT LPTSTR *lpOldPath
  270. )
  271. {
  272. DWORD BytesRequired;
  273. LPTSTR lpNewPath;
  274. HRESULT hr = S_OK;
  275. //
  276. // Prepend the address of the logon script to the path, so it can
  277. // reference other files.
  278. //
  279. *lpOldPath = AllocAndGetEnvironmentVariable( PATH );
  280. if (*lpOldPath == NULL) {
  281. return(FALSE);
  282. }
  283. BytesRequired = ( lstrlen(lpLogonPath) +
  284. lstrlen(*lpOldPath) +
  285. 2 // one for terminator, one for ';'
  286. ) * sizeof(TCHAR);
  287. lpNewPath = (LPTSTR)Alloc(BytesRequired);
  288. if (lpNewPath == NULL) {
  289. VerbosePrint(("PrependToPath: Failed to allocate %d bytes for modified path variable", BytesRequired));
  290. return(FALSE);
  291. }
  292. hr = StringCchCopy(lpNewPath, BytesRequired / sizeof(TCHAR), lpLogonPath);
  293. ASSERT(SUCCEEDED(hr));
  294. hr = StringCchCat(lpNewPath, BytesRequired / sizeof(TCHAR), DIRECTORY_SEPARATOR);
  295. ASSERT(SUCCEEDED(hr));
  296. hr = StringCchCat(lpNewPath, BytesRequired / sizeof(TCHAR), *lpOldPath);
  297. ASSERT(SUCCEEDED(hr));
  298. // Free( *lpOldPath );
  299. SetEnvironmentVariable(PATH, lpNewPath);
  300. Free(lpNewPath);
  301. return(TRUE);
  302. }
  303. //
  304. // Volatile Environment
  305. //
  306. #define VOLATILE_ENVIRONMENT TEXT("Volatile Environment")
  307. FILETIME g_LastWrite = {0,0};
  308. typedef BOOL (WINAPI *PFNREGENERATEUSERENVIRONMENT) (
  309. PVOID pPrevEnv, BOOL bSetCurrentEnv);
  310. //
  311. // This function checks if a volatile environment section
  312. // exists in the registry, and if so does the environment
  313. // need to be updated.
  314. //
  315. BOOL UpdateUserEnvironment (void)
  316. {
  317. PVOID pEnv;
  318. HKEY hKey;
  319. DWORD dwDisp, dwType, dwSize;
  320. BOOL bRebuildEnv = FALSE;
  321. TCHAR szClass[MAX_PATH];
  322. DWORD cchClass, dwSubKeys, dwMaxSubKey, dwMaxClass,dwValues;
  323. DWORD dwMaxValueName, dwMaxValueData, dwSecurityDescriptor;
  324. FILETIME LastWrite;
  325. //
  326. // Attempt to open the Volatile Environment key
  327. //
  328. if (RegOpenKeyEx (HKEY_CURRENT_USER,
  329. VOLATILE_ENVIRONMENT,
  330. 0,
  331. KEY_READ,
  332. &hKey) == ERROR_SUCCESS) {
  333. //
  334. // Query the key information for the LastWrite time.
  335. // This way we can update the environment only when
  336. // we really need to.
  337. //
  338. cchClass = MAX_PATH;
  339. if (RegQueryInfoKey(hKey,
  340. szClass,
  341. &cchClass,
  342. NULL,
  343. &dwSubKeys,
  344. &dwMaxSubKey,
  345. &dwMaxClass,
  346. &dwValues,
  347. &dwMaxValueName,
  348. &dwMaxValueData,
  349. &dwSecurityDescriptor,
  350. &LastWrite) == ERROR_SUCCESS) {
  351. //
  352. // If we haven't checked this key before,
  353. // then just store the values for next time.
  354. //
  355. if (g_LastWrite.dwLowDateTime == 0) {
  356. g_LastWrite.dwLowDateTime = LastWrite.dwLowDateTime;
  357. g_LastWrite.dwHighDateTime = LastWrite.dwHighDateTime;
  358. bRebuildEnv = TRUE;
  359. } else {
  360. //
  361. // Compare the last write times.
  362. //
  363. if (CompareFileTime (&LastWrite, &g_LastWrite) == 1) {
  364. g_LastWrite.dwLowDateTime = LastWrite.dwLowDateTime;
  365. g_LastWrite.dwHighDateTime = LastWrite.dwHighDateTime;
  366. bRebuildEnv = TRUE;
  367. }
  368. }
  369. }
  370. RegCloseKey (hKey);
  371. }
  372. //
  373. // Check if we need to rebuild the environment
  374. //
  375. if (bRebuildEnv) {
  376. HINSTANCE hInst;
  377. PFNREGENERATEUSERENVIRONMENT pRegUserEnv;
  378. hInst = LoadLibrary (TEXT("shell32.dll"));
  379. if (hInst) {
  380. pRegUserEnv = (PFNREGENERATEUSERENVIRONMENT) GetProcAddress(hInst, "RegenerateUserEnvironment");
  381. if (pRegUserEnv) {
  382. (*pRegUserEnv) (&pEnv, TRUE);
  383. }
  384. FreeLibrary (hInst);
  385. }
  386. }
  387. return TRUE;
  388. }
  389. // returns a pointer to the arguments in a cmd type path or pointer to
  390. // NULL if no args exist
  391. //
  392. // abc.exe xyz.txt -> xyz.txt
  393. // abc.exe -> ""
  394. //
  395. // Spaces in filenames must be quoted.
  396. // "A long name.txt" bar.txt -> bar.txt
  397. LPTSTR GetArgs(LPCTSTR pszPath)
  398. {
  399. BOOL fInQuotes = FALSE;
  400. if (!pszPath)
  401. return NULL;
  402. while (*pszPath)
  403. {
  404. if (*pszPath == TEXT('"'))
  405. fInQuotes = !fInQuotes;
  406. else if (!fInQuotes && *pszPath == TEXT(' '))
  407. return (LPTSTR)pszPath;
  408. pszPath = CharNext(pszPath);
  409. }
  410. return (LPTSTR)pszPath;
  411. }
  412. /***************************************************************************\
  413. * ExecApplication
  414. *
  415. * Execs an application
  416. *
  417. * Returns TRUE on success, FALSE on failure.
  418. *
  419. * 21-Aug-92 Davidc Created.
  420. \***************************************************************************/
  421. BOOL
  422. ExecApplication(
  423. LPTSTR pch,
  424. BOOL bFileNameOnly,
  425. BOOL bSyncApp,
  426. BOOL bShellExec,
  427. USHORT ShowState
  428. )
  429. {
  430. BOOL Result;
  431. WCHAR Localpch[ MAX_PATH+1 ];
  432. BOOL IsProcessExplorer = FALSE;
  433. HRESULT hr = S_OK;
  434. if ( (_wcsicmp( pch, L"explorer" ) == 0) ||
  435. (_wcsicmp( pch, L"explorer.exe" ) == 0 ) )
  436. {
  437. //
  438. // Explorer.exe might not be in the right spot on the path. Let's wire
  439. // it to the right spot.
  440. //
  441. IsProcessExplorer = TRUE ;
  442. if ( ExpandEnvironmentStrings( L"%SystemRoot%\\Explorer.EXE", Localpch, MAX_PATH ) )
  443. {
  444. pch = Localpch ;
  445. }
  446. WriteLog( TEXT("Changed explorer.exe to") );
  447. WriteLog( pch );
  448. }
  449. else
  450. {
  451. if ( ExpandEnvironmentStrings( pch, Localpch, MAX_PATH ) )
  452. {
  453. pch = Localpch;
  454. }
  455. }
  456. //
  457. // Applications can be launched via ShellExecuteEx or CreateProcess
  458. //
  459. if (bShellExec)
  460. {
  461. SHELLEXECUTEINFO ExecInfo;
  462. LPTSTR lpArgs = NULL;
  463. LPTSTR lpTemp;
  464. HINSTANCE hShell32;
  465. if (!g_pfnShellExecuteEx) {
  466. Result = FALSE;
  467. hShell32 = LoadLibrary(TEXT("shell32.dll"));
  468. // this handle is not closed..
  469. if (hShell32) {
  470. #ifdef UNICODE
  471. g_pfnShellExecuteEx = (PFNSHELLEXECUTEEX)GetProcAddress(hShell32, "ShellExecuteExW");
  472. #else
  473. g_pfnShellExecuteEx = (PFNSHELLEXECUTEEX)GetProcAddress(hShell32, "ShellExecuteExA");
  474. #endif
  475. if (g_pfnShellExecuteEx) {
  476. Result = TRUE;
  477. }
  478. }
  479. }
  480. else {
  481. Result = TRUE;
  482. }
  483. if (Result) {
  484. lpTemp = LocalAlloc (LPTR, (lstrlen(pch) + 1) * sizeof(TCHAR));
  485. if (!lpTemp) {
  486. return FALSE;
  487. }
  488. hr = StringCchCopy (lpTemp, lstrlen(pch) + 1, pch);
  489. ASSERT(SUCCEEDED(hr));
  490. if (!bFileNameOnly) {
  491. lpArgs = GetArgs (lpTemp);
  492. if (lpArgs) {
  493. if (*lpArgs) {
  494. *lpArgs = TEXT('\0');
  495. lpArgs++;
  496. } else {
  497. lpArgs = NULL;
  498. }
  499. }
  500. }
  501. PathUnquoteSpaces(lpTemp);
  502. ZeroMemory(&ExecInfo, sizeof(ExecInfo));
  503. ExecInfo.cbSize = sizeof(ExecInfo);
  504. ExecInfo.fMask = SEE_MASK_DOENVSUBST | SEE_MASK_FLAG_NO_UI |
  505. SEE_MASK_NOCLOSEPROCESS;
  506. ExecInfo.lpFile = lpTemp;
  507. ExecInfo.lpParameters = lpArgs;
  508. ExecInfo.nShow = ShowState;
  509. ExecInfo.lpVerb = TEXT("open");
  510. Result = g_pfnShellExecuteEx (&ExecInfo);
  511. if (Result) {
  512. //
  513. // If we are running this app synchronously, wait
  514. // for it to terminate.
  515. //
  516. if (bSyncApp) {
  517. WaitForSingleObject(ExecInfo.hProcess, INFINITE);
  518. }
  519. //
  520. // Close our handles to the process and thread
  521. //
  522. CloseHandle(ExecInfo.hProcess);
  523. }
  524. LocalFree (lpTemp);
  525. }
  526. }
  527. else
  528. {
  529. STARTUPINFO si;
  530. PROCESS_INFORMATION ProcessInformation;
  531. //
  532. // Initialize process startup info
  533. //
  534. si.cb = sizeof(STARTUPINFO);
  535. si.lpReserved = pch; // This tells progman it's the shell!
  536. si.lpTitle = pch;
  537. si.lpDesktop = NULL; // Not used
  538. si.dwX = si.dwY = si.dwXSize = si.dwYSize = 0L;
  539. si.dwFlags = STARTF_USESHOWWINDOW;
  540. si.wShowWindow = ShowState;
  541. si.lpReserved2 = NULL;
  542. si.cbReserved2 = 0;
  543. //
  544. // Start the app
  545. //
  546. Result = CreateProcess(
  547. bFileNameOnly ? pch : NULL, // Image name
  548. bFileNameOnly ? NULL : pch, // Command line
  549. NULL, // Default process protection
  550. NULL, // Default thread protection
  551. FALSE, // Don't inherit handles
  552. NORMAL_PRIORITY_CLASS,
  553. NULL, // Inherit environment
  554. NULL, // Inherit current directory
  555. &si,
  556. &ProcessInformation
  557. );
  558. if (!Result) {
  559. VerbosePrint(("Failed to execute <%S>, error = %d", pch, GetLastError()));
  560. // TS : For non console sessions, a app restriting process like AppSec or SAFER might not allow explorer.exe for remote session
  561. // In this case we cannot leave a Blue screen hanging around - so we should log-off in this case
  562. // Also we want this only for Server or Advanced Server where this scenario is relevant
  563. if ( IsPerOrProTerminalServer() == FALSE) {
  564. if ((NtCurrentPeb()->SessionId != 0) && (IsProcessExplorer == TRUE)) {
  565. TCHAR Title[MAX_STRING_BYTES];
  566. TCHAR Message[MAX_STRING_BYTES];
  567. #if DBG
  568. DbgPrint("Userinit : TS : Failed to launch explorer.exe for a Remote Session. Doing ExitWindowsEx to logoff. \n");
  569. #endif
  570. // Display a MessageBox saying why we log off
  571. LoadString( NULL, IDS_LOGON_FAILED, Title, MAX_STRING_BYTES );
  572. LoadString(NULL, IDS_ERROR_SHELL_FAILED, Message, MAX_STRING_BYTES );
  573. MessageBox(NULL, Message, Title, MB_OK);
  574. ExitWindowsEx(EWX_LOGOFF, 0);
  575. }
  576. }
  577. } else {
  578. //
  579. // If we are running this app synchronously, wait
  580. // for it to terminate.
  581. //
  582. if (bSyncApp) {
  583. WaitForSingleObject(ProcessInformation.hProcess, INFINITE);
  584. }
  585. //
  586. // Close our handles to the process and thread
  587. //
  588. CloseHandle(ProcessInformation.hProcess);
  589. CloseHandle(ProcessInformation.hThread);
  590. }
  591. }
  592. return(Result);
  593. }
  594. /***************************************************************************\
  595. * ExecProcesses
  596. *
  597. * Read the registry for a list of system processes and start them up.
  598. *
  599. * Returns number of processes successfully started.
  600. *
  601. * 3-Mar-97 Eric Flo Rewrote
  602. \***************************************************************************/
  603. DWORD
  604. ExecProcesses(
  605. LPTSTR pszKeyName,
  606. LPTSTR pszDefault,
  607. BOOL bMachine,
  608. BOOL bSync, // Should we wait until the process finish?
  609. BOOL bMinimize // Should we use the SW_SHOWMINNOACTIVE flag
  610. )
  611. {
  612. LPTSTR pchData, pchCmdLine, pchT;
  613. DWORD cbCopied;
  614. DWORD dwExecuted = 0 ;
  615. HKEY hKey;
  616. DWORD dwType, dwSize = (MAX_PATH * sizeof(TCHAR));
  617. USHORT showstate = (UINT) (bMinimize ? SW_SHOWMINNOACTIVE : SW_SHOWNORMAL);
  618. HRESULT hr = S_OK;
  619. BOOL bRestore = FALSE;
  620. //
  621. // Alloc a buffer to work with
  622. //
  623. pchData = LocalAlloc (LPTR, dwSize);
  624. if (!pchData) {
  625. return 0;
  626. }
  627. //
  628. // Set the default value
  629. //
  630. Restore:
  631. if (pszDefault) {
  632. hr = StringCchCopy (pchData, MAX_PATH, pszDefault);
  633. if(FAILED(hr)){
  634. LocalFree(pchData);
  635. SetLastError(HRESULT_CODE(hr));
  636. return 0;
  637. }
  638. }
  639. //
  640. // Check for the requested value in the registry.
  641. //
  642. if (RegOpenKeyEx ((bMachine ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER),
  643. WINLOGON_KEY,
  644. 0, KEY_READ, &hKey) == ERROR_SUCCESS) {
  645. dwSize = (MAX_PATH * sizeof(TCHAR));
  646. if (ERROR_SUCCESS == RegQueryValueEx (hKey, pszKeyName, NULL, &dwType, (LPBYTE) pchData, &dwSize))
  647. {
  648. if ((REG_SZ != dwType) || (dwSize < 2) || (pchData[dwSize/sizeof(TCHAR) - 1]))
  649. {
  650. //
  651. // Restore the default value
  652. //
  653. if (pszDefault) {
  654. hr = StringCchCopy (pchData, MAX_PATH, pszDefault);
  655. ASSERT(SUCCEEDED(hr)); // Since the same one above succeeded
  656. }
  657. else {
  658. pchData[0] = 0;
  659. }
  660. }
  661. }
  662. // else the buffer wasn't touched so no need to restore
  663. RegCloseKey (hKey);
  664. }
  665. if (!bRestore)
  666. {
  667. //
  668. // Check for policy override if this is a user action
  669. //
  670. if (!bMachine)
  671. {
  672. if (RegOpenKeyEx (HKEY_CURRENT_USER, WINLOGON_POLICY_KEY,
  673. 0, KEY_READ, &hKey) == ERROR_SUCCESS) {
  674. dwSize = (MAX_PATH * sizeof(TCHAR));
  675. cbCopied = RegQueryValueEx (hKey, pszKeyName, NULL, &dwType, (LPBYTE) pchData, &dwSize);
  676. RegCloseKey (hKey);
  677. if (ERROR_SUCCESS == cbCopied)
  678. {
  679. if ((REG_SZ != dwType) || (dwSize < 2) || (pchData[dwSize/sizeof(TCHAR) - 1]))
  680. {
  681. bRestore = TRUE;
  682. goto Restore;
  683. }
  684. }
  685. // else the buffer wasn't touched so no need to restore
  686. }
  687. }
  688. }
  689. //
  690. // If the command line(s) is still null, exit now.
  691. //
  692. if (*pchData == TEXT('\0')) {
  693. LocalFree(pchData);
  694. return 0;
  695. }
  696. //
  697. // Walk through the command line(s) executing the app(s)
  698. //
  699. pchCmdLine = pchT = pchData;
  700. while (*pchT) {
  701. while (*pchT && *pchT != TEXT(',')) {
  702. pchT++;
  703. }
  704. if (*pchT == ',') {
  705. *pchT = TEXT('\0');
  706. pchT++;
  707. }
  708. //
  709. // Skip any leading spaces.
  710. //
  711. while (*pchCmdLine == TEXT(' ')) {
  712. pchCmdLine++;
  713. }
  714. //
  715. // We have something... exec this application.
  716. //
  717. if (ExecApplication(pchCmdLine, FALSE, bSync, FALSE, showstate)) {
  718. dwExecuted++;
  719. }
  720. pchCmdLine = pchT;
  721. }
  722. LocalFree(pchData);
  723. return dwExecuted ;
  724. }
  725. /***************************************************************************\
  726. * SearchAndAllocPath
  727. *
  728. * Version of SearchPath that allocates the return string.
  729. *
  730. * Returns pointer to full path of file or NULL if not found.
  731. *
  732. * The returned buffer should be free using Free()
  733. *
  734. * History:
  735. * 09-Dec-92 Davidc Created
  736. *
  737. \***************************************************************************/
  738. LPTSTR
  739. SearchAndAllocPath(
  740. LPTSTR lpPath,
  741. LPTSTR lpFileName,
  742. LPTSTR lpExtension,
  743. LPTSTR *lpFilePart
  744. )
  745. {
  746. LPTSTR Buffer;
  747. DWORD LengthRequired;
  748. DWORD LengthUsed;
  749. DWORD BytesRequired;
  750. //
  751. // Allocate a buffer to hold the full filename
  752. //
  753. LengthRequired = MAX_PATH;
  754. BytesRequired = (LengthRequired * sizeof(TCHAR));
  755. Buffer = Alloc(BytesRequired);
  756. if (Buffer == NULL) {
  757. UIPrint(("SearchAndAllocPath: Failed to allocate %d bytes for file name", BytesRequired));
  758. return(NULL);
  759. }
  760. //
  761. // Go search for the file
  762. //
  763. LengthUsed = SearchPath(
  764. lpPath,
  765. lpFileName,
  766. lpExtension,
  767. LengthRequired,
  768. Buffer,
  769. lpFilePart);
  770. if (LengthUsed == 0) {
  771. VerbosePrint(("SearchAndAllocPath: Path <%S>, file <%S>, extension <%S> not found, error = %d", lpPath, lpFileName, lpExtension, GetLastError()));
  772. Free(Buffer);
  773. return(NULL);
  774. }
  775. if (LengthUsed > LengthRequired - 1) {
  776. UIPrint(("SearchAndAllocPath: Unexpected result from SearchPath. Length passed = %d, length used = %d (expected %d)", LengthRequired, LengthUsed, LengthRequired - 1));
  777. Free(Buffer);
  778. return(NULL);
  779. }
  780. return(Buffer);
  781. }
  782. BOOL
  783. DisableScriptZoneSecurityCheck()
  784. {
  785. BOOL bSucceeded;
  786. //
  787. // To make the shell skip the zone security check for launching scripts, we use
  788. // a special environment variable honored by the shell for this purpose and
  789. // set it to a specific value
  790. //
  791. bSucceeded = SetEnvironmentVariable(SCRIPT_ZONE_CHECK_VARIABLE, SCRIPT_ZONE_CHECK_DISABLE);
  792. return bSucceeded;
  793. }
  794. BOOL
  795. EnableScriptZoneSecurityCheck()
  796. {
  797. BOOL bSucceeded;
  798. //
  799. // Clear the environment variable that disables the security check
  800. //
  801. bSucceeded = SetEnvironmentVariable(SCRIPT_ZONE_CHECK_VARIABLE, NULL);
  802. if ( ! bSucceeded )
  803. {
  804. //
  805. // If we failed to clear it, it may be that this is because the
  806. // environment variable wasn't set in the first place, in which
  807. // case we can ignore the error since we are in the desired state
  808. //
  809. LONG Status = GetLastError();
  810. if ( ERROR_ENVVAR_NOT_FOUND == Status )
  811. {
  812. bSucceeded = TRUE;
  813. }
  814. }
  815. return bSucceeded;
  816. }
  817. /***************************************************************************\
  818. * ExecScript
  819. *
  820. * Attempts to run the command script or exe lpScript in the directory lpPath.
  821. * If path is not specified then the default windows search path is used.
  822. *
  823. * This routine is basically a wrapper for CreateProcess. CreateProcess always
  824. * assumes a .exe extension for files without extensions. It will run .cmd
  825. * and .bat files but it keys off the .cmd and .bat extension. So we must go
  826. * search for the file first and add the extension before calling CreateProcess.
  827. *
  828. * Returns TRUE if the script began executing successfully.
  829. * Returns FALSE if we can't find the script in the path specified
  830. * or something fails.
  831. *
  832. * History:
  833. * 09-Dec-92 Davidc Created
  834. *
  835. \***************************************************************************/
  836. BOOL
  837. ExecScript(
  838. LPTSTR lpPath OPTIONAL,
  839. LPTSTR lpScript,
  840. BOOL bSyncApp,
  841. BOOL bShellExec
  842. )
  843. {
  844. BOOL Result;
  845. DWORD i;
  846. USHORT uFlags;
  847. LPTSTR lpFullName;
  848. DWORD BytesRequired;
  849. HRESULT hr = S_OK;
  850. //
  851. // First try and execute the raw script file name
  852. //
  853. if (lpPath != NULL) {
  854. BytesRequired = (lstrlen(lpPath) +
  855. lstrlen(PATH_SEPARATOR) +
  856. lstrlen(lpScript) +
  857. 1)
  858. * sizeof(TCHAR);
  859. lpFullName = Alloc(BytesRequired);
  860. if (lpFullName == NULL) {
  861. UIPrint(("ExecScript failed to allocate %d bytes for full script name", BytesRequired));
  862. return(FALSE);
  863. }
  864. hr = StringCchCopy(lpFullName, BytesRequired / sizeof(TCHAR), lpPath);
  865. ASSERT(SUCCEEDED(hr));
  866. hr = StringCchCat(lpFullName, BytesRequired / sizeof(TCHAR), PATH_SEPARATOR);
  867. ASSERT(SUCCEEDED(hr));
  868. hr = StringCchCat(lpFullName, BytesRequired / sizeof(TCHAR), lpScript);
  869. ASSERT(SUCCEEDED(hr));
  870. } else {
  871. lpFullName = lpScript;
  872. }
  873. uFlags = SW_SHOWNORMAL;
  874. if (!bSyncApp) {
  875. uFlags |= SW_SHOWMINNOACTIVE;
  876. }
  877. if (RunScriptHidden(HKEY_CURRENT_USER, TEXT("HideLegacyLogonScripts"), FALSE)) {
  878. uFlags = SW_HIDE;
  879. }
  880. //
  881. // Let CreateProcess have a hack at the raw script path and name.
  882. //
  883. Result = ExecApplication(lpFullName, FALSE, bSyncApp, bShellExec, uFlags);
  884. //
  885. // Free up the full name buffer
  886. //
  887. if (lpFullName != lpScript) {
  888. Free(lpFullName);
  889. }
  890. if (!Result) {
  891. //
  892. // Create process couldn't find it so add each script extension in
  893. // turn and try and execute the full script name.
  894. //
  895. // Only bother with this procedure if the script name doesn't
  896. // already contain an extension
  897. //
  898. BOOL ExtensionPresent = FALSE;
  899. LPTSTR p = lpScript;
  900. while (*p) {
  901. if (*p == EXTENSION_SEPARATOR_CHAR) {
  902. ExtensionPresent = TRUE;
  903. break;
  904. }
  905. p = CharNext(p);
  906. }
  907. if (ExtensionPresent) {
  908. VerbosePrint(("ExecScript: Skipping search path because script name contains extension"));
  909. } else {
  910. for (i = 0; i < sizeof(ScriptExtensions)/sizeof(ScriptExtensions[0]); i++) {
  911. lpFullName = SearchAndAllocPath(
  912. lpPath,
  913. lpScript,
  914. ScriptExtensions[i],
  915. NULL);
  916. if (lpFullName != NULL) {
  917. //
  918. // We found the file, go execute it
  919. //
  920. Result = ExecApplication(lpFullName, FALSE, bSyncApp, bShellExec, uFlags);
  921. //
  922. // Free the full path buffer
  923. //
  924. Free(lpFullName);
  925. return(Result);
  926. }
  927. }
  928. }
  929. }
  930. return(Result);
  931. }
  932. BOOL RunScriptHidden(HKEY hKeyRoot, LPTSTR lpValue, BOOL bDefault)
  933. {
  934. BOOL bResult;
  935. HKEY hKey;
  936. DWORD dwType, dwSize;
  937. //
  938. // Set the default
  939. //
  940. bResult = bDefault;
  941. //
  942. // Check for a preference
  943. //
  944. if (RegOpenKeyEx (hKeyRoot, WINLOGON_KEY, 0,
  945. KEY_READ, &hKey) == ERROR_SUCCESS) {
  946. dwSize = sizeof(bResult);
  947. RegQueryValueEx (hKey, lpValue, NULL, &dwType,
  948. (LPBYTE) &bResult, &dwSize);
  949. RegCloseKey (hKey);
  950. }
  951. //
  952. // Check for a policy
  953. //
  954. if (RegOpenKeyEx (hKeyRoot, WINLOGON_POLICY_KEY, 0,
  955. KEY_READ, &hKey) == ERROR_SUCCESS) {
  956. dwSize = sizeof(bResult);
  957. RegQueryValueEx (hKey, lpValue, NULL, &dwType,
  958. (LPBYTE) &bResult, &dwSize);
  959. RegCloseKey (hKey);
  960. }
  961. return bResult;
  962. }
  963. /***************************************************************************\
  964. * RunLogonScript
  965. *
  966. * Starts the logon script
  967. *
  968. * Returns TRUE on success, FALSE on failure
  969. *
  970. * History:
  971. * 21-Aug-92 Davidc Created
  972. *
  973. \***************************************************************************/
  974. BOOL
  975. RunLogonScript(
  976. LPTSTR lpLogonServer OPTIONAL,
  977. LPTSTR lpLogonScript,
  978. BOOL bSyncApp,
  979. BOOL bShellExec
  980. )
  981. {
  982. LPTSTR lpLogonPath;
  983. LPTSTR lpOldPath;
  984. DWORD BytesRequired;
  985. BOOL Result;
  986. WIN32_FILE_ATTRIBUTE_DATA fad;
  987. HRESULT hr = S_OK;
  988. HANDLE hToken;
  989. if (!lpLogonScript) {
  990. return TRUE;
  991. }
  992. //
  993. // Skip logon script if cross forest logon
  994. //
  995. if (OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &hToken))
  996. {
  997. hr = CheckXForestLogon(hToken);
  998. CloseHandle(hToken);
  999. if (hr == S_FALSE)
  1000. {
  1001. return TRUE;
  1002. }
  1003. }
  1004. //
  1005. // if the logon server exists, look for the logon scripts on
  1006. // \\<LogonServer>\NETLOGON\<ScriptName>
  1007. //
  1008. if ((lpLogonServer != NULL) && (lpLogonServer[0] != 0)) {
  1009. BytesRequired = ( lstrlen(SERVER_PREFIX) +
  1010. lstrlen(lpLogonServer) +
  1011. lstrlen(SERVER_SCRIPT_PATH) +
  1012. 1
  1013. ) * sizeof(TCHAR);
  1014. lpLogonPath = (LPTSTR)Alloc(BytesRequired);
  1015. if (lpLogonPath == NULL) {
  1016. UIPrint(("RunLogonScript: Failed to allocate %d bytes for remote logon script path", BytesRequired));
  1017. return(FALSE);
  1018. }
  1019. hr = StringCchCopy(lpLogonPath, BytesRequired / sizeof(TCHAR), SERVER_PREFIX);
  1020. ASSERT(SUCCEEDED(hr));
  1021. hr = StringCchCat(lpLogonPath, BytesRequired / sizeof(TCHAR), lpLogonServer);
  1022. ASSERT(SUCCEEDED(hr));
  1023. hr = StringCchCat(lpLogonPath, BytesRequired / sizeof(TCHAR), SERVER_SCRIPT_PATH);
  1024. ASSERT(SUCCEEDED(hr));
  1025. if (GetFileAttributesEx (lpLogonPath, GetFileExInfoStandard, &fad)) {
  1026. BOOL bChangedPath;
  1027. Result = PrependToPath( lpLogonPath, &lpOldPath );
  1028. bChangedPath = Result;
  1029. if (Result) {
  1030. VerbosePrint(("Successfully prepended <%S> to path", lpLogonPath));
  1031. } else {
  1032. VerbosePrint(("Cannot prepend <%S> path.",lpLogonPath));
  1033. }
  1034. //
  1035. // Try and execute the app/script specified by lpLogonScript
  1036. // in the directory specified by lpLogonPath
  1037. //
  1038. Result = ExecScript(lpLogonPath, lpLogonScript, bSyncApp, bShellExec);
  1039. if (Result) {
  1040. VerbosePrint(("Successfully executed logon script <%S> in directory <%S>", lpLogonScript, lpLogonPath));
  1041. } else {
  1042. VerbosePrint(("Cannot start logon script <%S> on LogonServer <%S>. Trying local path.", lpLogonScript, lpLogonServer));
  1043. }
  1044. //
  1045. // Put the path back the way it was
  1046. //
  1047. if ( bChangedPath )
  1048. {
  1049. SetEnvironmentVariable(PATH, lpOldPath);
  1050. }
  1051. Free(lpOldPath);
  1052. } else {
  1053. Result = FALSE;
  1054. }
  1055. //
  1056. // Free up the buffer
  1057. //
  1058. Free(lpLogonPath);
  1059. //
  1060. // If the script started successfully we're done, otherwise
  1061. // drop through and try to find the script locally
  1062. //
  1063. if (Result) {
  1064. if (bSyncApp) {
  1065. //
  1066. // Check that the volatile environment hasn't changed.
  1067. //
  1068. UpdateUserEnvironment();
  1069. }
  1070. return(TRUE);
  1071. }
  1072. }
  1073. //
  1074. // Try to find the scripts on <system dir>\repl\import\scripts\<scriptname>
  1075. //
  1076. BytesRequired = GetSystemDirectory(NULL, 0) * sizeof(TCHAR);
  1077. if (BytesRequired == 0) {
  1078. UIPrint(("RunLogonScript: GetSystemDirectory failed, error = %d", GetLastError()));
  1079. return(FALSE);
  1080. }
  1081. BytesRequired += ( lstrlen(LOCAL_SCRIPT_PATH) + 1
  1082. // BytesRequired does not include space for terminator
  1083. ) * sizeof(TCHAR);
  1084. lpLogonPath = (LPTSTR)Alloc(BytesRequired);
  1085. if (lpLogonPath == NULL) {
  1086. UIPrint(("RunLogonScript failed to allocate %d bytes for logon script path", BytesRequired));
  1087. return(FALSE);
  1088. }
  1089. Result = FALSE;
  1090. if (GetSystemDirectory(lpLogonPath, BytesRequired / sizeof(TCHAR))) {
  1091. hr = StringCchCat(lpLogonPath, BytesRequired / sizeof(TCHAR), LOCAL_SCRIPT_PATH);
  1092. ASSERT(SUCCEEDED(hr));
  1093. Result = PrependToPath( lpLogonPath, &lpOldPath );
  1094. if (Result) {
  1095. VerbosePrint(("Successfully prepended <%S> to path", lpLogonPath));
  1096. } else {
  1097. VerbosePrint(("Cannot prepend <%S> path.",lpLogonPath));
  1098. }
  1099. //
  1100. // Try and execute the app/script specified by lpLogonScript
  1101. // in the directory specified by lpLogonPath
  1102. //
  1103. Result = ExecScript(lpLogonPath, lpLogonScript, bSyncApp, bShellExec);
  1104. if (Result) {
  1105. VerbosePrint(("Successfully executed logon script <%S> in directory <%S>", lpLogonScript, lpLogonPath));
  1106. } else {
  1107. VerbosePrint(("Cannot start logon script <%S> on local path <%S>.", lpLogonScript, lpLogonPath));
  1108. }
  1109. //
  1110. // Put the path back the way it was
  1111. //
  1112. SetEnvironmentVariable(PATH, lpOldPath);
  1113. Free(lpOldPath);
  1114. } else {
  1115. UIPrint(("RunLogonScript: GetSystemDirectory failed, error = %d", GetLastError()));
  1116. }
  1117. //
  1118. // Free up the buffer
  1119. //
  1120. Free(lpLogonPath);
  1121. //
  1122. // Check that the volatile environment hasn't changed.
  1123. //
  1124. if (Result && bSyncApp) {
  1125. UpdateUserEnvironment();
  1126. }
  1127. return(Result);
  1128. }
  1129. #define SCR_STARTUP L"Startup"
  1130. #define SCR_SHUTDOWN L"Shutdown"
  1131. #define SCR_LOGON L"Logon"
  1132. #define SCR_LOGOFF L"Logoff"
  1133. DWORD
  1134. ScrExecGPOListFromReg( LPWSTR szType,
  1135. BOOL bMachine,
  1136. BOOL bSync,
  1137. BOOL bHidden,
  1138. BOOL bRunMin,
  1139. HANDLE hEventLog );
  1140. BOOL
  1141. RunGPOScripts(
  1142. LPTSTR lpGPOScriptType
  1143. )
  1144. {
  1145. HKEY hKeyScripts;
  1146. HKEY hKeyRoot;
  1147. BOOL bSync = TRUE;
  1148. BOOL bRunMin = TRUE;
  1149. BOOL bHide;
  1150. HANDLE hEventLog = NULL;
  1151. BOOL bMachine;
  1152. BOOL bResult = FALSE;
  1153. DWORD dwError;
  1154. //
  1155. // Ensure that the shell's checks for ie zones are disabled
  1156. // since this script is trusted by an administrator to execute
  1157. //
  1158. bResult = DisableScriptZoneSecurityCheck();
  1159. if ( ! bResult )
  1160. {
  1161. goto RunGPOScripts_exit;
  1162. }
  1163. //
  1164. // Register with Event Log -- if the event source is not
  1165. // available, we will continue and simply not log script
  1166. // events during execution -- a NULL return indicates this
  1167. // below, and we will simply pass this NULL to other functions
  1168. // which will handle it properly
  1169. //
  1170. hEventLog = RegisterEventSource( 0, EVENT_SOURCE_NAME );
  1171. //
  1172. // Preliminary work to see if the scripts should be
  1173. // run sync or async and to decide what the appropriate
  1174. // root key is
  1175. //
  1176. if (CompareString(LOCALE_INVARIANT, NORM_IGNORECASE, lpGPOScriptType, -1, SCR_LOGON, -1) == CSTR_EQUAL)
  1177. {
  1178. hKeyRoot = HKEY_CURRENT_USER;
  1179. bHide = RunScriptHidden(hKeyRoot, TEXT("HideLogonScripts"), TRUE);
  1180. bSync = RunLogonScriptSync();
  1181. bMachine = FALSE;
  1182. if (bSync && !bHide)
  1183. {
  1184. bRunMin = FALSE;
  1185. }
  1186. }
  1187. else if (CompareString(LOCALE_INVARIANT, NORM_IGNORECASE, lpGPOScriptType, -1, SCR_LOGOFF, -1) == CSTR_EQUAL)
  1188. {
  1189. hKeyRoot = HKEY_CURRENT_USER;
  1190. bHide = RunScriptHidden(hKeyRoot, TEXT("HideLogoffScripts"), TRUE);
  1191. bMachine = FALSE;
  1192. if (!bHide)
  1193. {
  1194. bRunMin = FALSE;
  1195. }
  1196. }
  1197. else if (CompareString(LOCALE_INVARIANT, NORM_IGNORECASE, lpGPOScriptType, -1, SCR_STARTUP, -1) == CSTR_EQUAL)
  1198. {
  1199. hKeyRoot = HKEY_LOCAL_MACHINE;
  1200. bHide = RunScriptHidden(hKeyRoot, TEXT("HideStartupScripts"), TRUE);
  1201. bSync = RunStartupScriptSync();
  1202. bMachine = TRUE;
  1203. if (bSync && !bHide)
  1204. {
  1205. bRunMin = FALSE;
  1206. }
  1207. }
  1208. else if (CompareString(LOCALE_INVARIANT, NORM_IGNORECASE, lpGPOScriptType, -1, SCR_SHUTDOWN, -1) == CSTR_EQUAL)
  1209. {
  1210. hKeyRoot = HKEY_LOCAL_MACHINE;
  1211. bHide = RunScriptHidden(hKeyRoot, TEXT("HideShutdownScripts"), TRUE);
  1212. bMachine = TRUE;
  1213. if (!bHide)
  1214. {
  1215. bRunMin = FALSE;
  1216. }
  1217. }
  1218. else
  1219. {
  1220. goto RunGPOScripts_exit;
  1221. }
  1222. dwError = ScrExecGPOListFromReg(lpGPOScriptType,
  1223. bMachine,
  1224. bSync,
  1225. bHide,
  1226. bRunMin,
  1227. hEventLog );
  1228. bResult = ( dwError == ERROR_SUCCESS );
  1229. RunGPOScripts_exit:
  1230. if (hEventLog)
  1231. {
  1232. DeregisterEventSource(hEventLog);
  1233. }
  1234. return bResult;
  1235. }
  1236. /***************************************************************************\
  1237. * RunMprLogonScripts
  1238. *
  1239. * Starts the network provider logon scripts
  1240. * The passed string is a multi-sz - we exec each script in turn.
  1241. *
  1242. * Returns TRUE on success, FALSE on failure
  1243. *
  1244. * History:
  1245. * 21-Aug-92 Davidc Created
  1246. *
  1247. \***************************************************************************/
  1248. BOOL
  1249. RunMprLogonScripts(
  1250. LPTSTR lpLogonScripts,
  1251. BOOL bSyncApp
  1252. )
  1253. {
  1254. BOOL Result;
  1255. if (lpLogonScripts != NULL) {
  1256. DWORD Length;
  1257. do {
  1258. Length = lstrlen(lpLogonScripts);
  1259. if (Length != 0) {
  1260. Result = ExecScript(NULL, lpLogonScripts, bSyncApp, FALSE);
  1261. if (Result) {
  1262. VerbosePrint(("Successfully executed mpr logon script <%S>", lpLogonScripts));
  1263. if (bSyncApp) {
  1264. //
  1265. // Check that the volatile environment hasn't changed.
  1266. //
  1267. UpdateUserEnvironment();
  1268. }
  1269. } else {
  1270. VerbosePrint(("Cannot start mpr logon script <%S>", lpLogonScripts));
  1271. }
  1272. }
  1273. lpLogonScripts += (Length + 1);
  1274. } while (Length != 0);
  1275. }
  1276. return(TRUE);
  1277. }
  1278. /***************************************************************************\
  1279. * AllocAndGetEnvironmentMultiSz
  1280. *
  1281. * Gets an environment variable's value that's assumed to be an
  1282. * encoded multi-sz and decodes it into an allocated return buffer.
  1283. * Variable should have been written with SetEnvironmentMultiSz() (winlogon)
  1284. *
  1285. * Returns pointer to environment variable or NULL on failure
  1286. *
  1287. * The returned buffer should be free using Free()
  1288. *
  1289. * History:
  1290. * 01-15-93 Davidc Created
  1291. *
  1292. \***************************************************************************/
  1293. #define TERMINATOR_REPLACEMENT TEXT(',')
  1294. LPTSTR
  1295. AllocAndGetEnvironmentMultiSz(
  1296. LPTSTR lpName
  1297. )
  1298. {
  1299. LPTSTR Buffer;
  1300. LPTSTR p, q;
  1301. Buffer = AllocAndGetEnvironmentVariable(lpName);
  1302. if (Buffer == NULL) {
  1303. return(NULL);
  1304. }
  1305. //
  1306. // Now decode the string - we can do this in place since the string
  1307. // will always get smaller
  1308. //
  1309. p = Buffer;
  1310. q = Buffer;
  1311. while (*p) {
  1312. if (*p == TERMINATOR_REPLACEMENT) {
  1313. p ++;
  1314. if (*p != TERMINATOR_REPLACEMENT) {
  1315. p --;
  1316. *p = 0;
  1317. }
  1318. }
  1319. if (p != q) {
  1320. *q = *p;
  1321. }
  1322. p ++;
  1323. q ++;
  1324. }
  1325. ASSERT(q <= p);
  1326. //
  1327. // Copy terminator
  1328. //
  1329. if (q != p) {
  1330. *q = 0;
  1331. }
  1332. return(Buffer);
  1333. }
  1334. /***************************************************************************\
  1335. * CheckVideoSelection
  1336. *
  1337. * History:
  1338. * 15-Mar-93 Andreva Created.
  1339. \***************************************************************************/
  1340. VOID
  1341. CheckVideoSelection(
  1342. HINSTANCE hInstance
  1343. )
  1344. {
  1345. //
  1346. // First check if we are in a detection mode.
  1347. // If we are, spawn the applet and let the user pick the mode.
  1348. //
  1349. // Otherwise, check to see if the display was initialized properly.
  1350. // We may want to move this to a more appropriate place at a later date.
  1351. //
  1352. // Andreva
  1353. //
  1354. NTSTATUS Status;
  1355. HANDLE HkRegistry;
  1356. OBJECT_ATTRIBUTES ObjectAttributes;
  1357. UNICODE_STRING UnicodeString;
  1358. TCHAR achDispMode[512];
  1359. TCHAR achDisp[512];
  1360. TCHAR achExec[MAX_PATH];
  1361. DWORD Mesg = 0;
  1362. LPTSTR psz = NULL;
  1363. DWORD cb, dwType;
  1364. DWORD data;
  1365. if ( NtCurrentPeb()->SessionId != 0 ) {
  1366. // Only do this for Console
  1367. return;
  1368. }
  1369. //
  1370. // Check for a new driver installation
  1371. //
  1372. RtlInitUnicodeString(&UnicodeString,
  1373. L"\\Registry\\Machine\\System\\CurrentControlSet"
  1374. L"\\Control\\GraphicsDrivers\\DetectDisplay");
  1375. InitializeObjectAttributes(&ObjectAttributes,
  1376. &UnicodeString,
  1377. OBJ_CASE_INSENSITIVE,
  1378. NULL,
  1379. NULL);
  1380. Status = NtOpenKey(&HkRegistry,
  1381. GENERIC_READ | GENERIC_WRITE | DELETE,
  1382. &ObjectAttributes);
  1383. if (!NT_SUCCESS(Status)) {
  1384. //
  1385. // Check for a new driver installation
  1386. //
  1387. RtlInitUnicodeString(&UnicodeString,
  1388. L"\\Registry\\Machine\\System\\CurrentControlSet"
  1389. L"\\Control\\GraphicsDrivers\\NewDisplay");
  1390. InitializeObjectAttributes(&ObjectAttributes,
  1391. &UnicodeString,
  1392. OBJ_CASE_INSENSITIVE,
  1393. NULL,
  1394. NULL);
  1395. Status = NtOpenKey(&HkRegistry,
  1396. GENERIC_READ | GENERIC_WRITE | DELETE,
  1397. &ObjectAttributes);
  1398. if (!NT_SUCCESS(Status)) {
  1399. //
  1400. // Check for an invalid driver (like a 3.51 driver) or a badly
  1401. // configured driver.
  1402. //
  1403. RtlInitUnicodeString(&UnicodeString,
  1404. L"\\Registry\\Machine\\System\\CurrentControlSet"
  1405. L"\\Control\\GraphicsDrivers\\InvalidDisplay");
  1406. InitializeObjectAttributes(&ObjectAttributes,
  1407. &UnicodeString,
  1408. OBJ_CASE_INSENSITIVE,
  1409. NULL,
  1410. NULL);
  1411. Status = NtOpenKey(&HkRegistry,
  1412. GENERIC_READ | GENERIC_WRITE | DELETE,
  1413. &ObjectAttributes);
  1414. }
  1415. }
  1416. //
  1417. // If any of the the error keys were opened successfully, then close the
  1418. // key and spawn the applet (we only delete the invalid display key, not
  1419. // the DetectDisplay key !)
  1420. //
  1421. if (NT_SUCCESS(Status)) {
  1422. NtClose(HkRegistry);
  1423. LoadString(hInstance,
  1424. IDS_DISPLAYAPPLET,
  1425. achExec, sizeof(achExec) / sizeof( TCHAR ));
  1426. ExecApplication(achExec, FALSE, TRUE, FALSE, SW_SHOWNORMAL);
  1427. }
  1428. }
  1429. /***************************************************************************\
  1430. * InitializeMisc
  1431. *
  1432. * History:
  1433. * 14-Jul-95 EricFlo Created.
  1434. \***************************************************************************/
  1435. void InitializeMisc (HINSTANCE hInstance)
  1436. {
  1437. HKEY hkeyMM;
  1438. DWORD dwTempFile, cbTempFile, dwType;
  1439. TCHAR achExec[MAX_PATH];
  1440. //
  1441. // check the page file. If there is not one, then spawn the vm applet
  1442. //
  1443. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, szMemMan, 0, KEY_READ,
  1444. &hkeyMM) == ERROR_SUCCESS) {
  1445. cbTempFile = sizeof(dwTempFile);
  1446. if (RegQueryValueEx (hkeyMM, szNoPageFile, NULL, &dwType,
  1447. (LPBYTE) &dwTempFile, &cbTempFile) != ERROR_SUCCESS ||
  1448. dwType != REG_DWORD || cbTempFile != sizeof(dwTempFile)) {
  1449. dwTempFile = 0;
  1450. }
  1451. RegCloseKey(hkeyMM);
  1452. } else
  1453. dwTempFile = 0;
  1454. if (dwTempFile == 1) {
  1455. LoadString(hInstance, IDS_VMAPPLET, achExec, sizeof(achExec) / sizeof( TCHAR ));
  1456. ExecProcesses(TEXT("vmapplet"), achExec, TRUE, FALSE, TRUE);
  1457. }
  1458. //
  1459. // Tell the user if he has an invalid video selection.
  1460. //
  1461. CheckVideoSelection(hInstance);
  1462. //
  1463. // Notify other system components that a new
  1464. // user has logged into the workstation.
  1465. //
  1466. NewLogonNotify();
  1467. }
  1468. #ifdef LOGGING
  1469. #define DATEFORMAT TEXT("%d-%d %.2d:%.2d:%.2d:%.3d ")
  1470. /***************************************************************************\
  1471. * _WriteLog
  1472. *
  1473. * History:
  1474. * 22-Mar-93 Robertre Created.
  1475. \***************************************************************************/
  1476. void
  1477. _WriteLog(
  1478. LPCTSTR LogString
  1479. )
  1480. {
  1481. TCHAR Buffer[MAX_PATH];
  1482. SYSTEMTIME st;
  1483. TCHAR FormatString[MAX_PATH];
  1484. #_#_lstrcpy( FormatString, DATEFORMAT );
  1485. #_#_lstrcat( FormatString, LogString );
  1486. #_#_lstrcat( FormatString, TEXT("\r\n") );
  1487. GetLocalTime( &st );
  1488. //
  1489. // Construct the message
  1490. //
  1491. #_#_wsprintf( Buffer,
  1492. FormatString,
  1493. st.wMonth,
  1494. st.wDay,
  1495. st.wHour,
  1496. st.wMinute,
  1497. st.wSecond,
  1498. st.wMilliseconds
  1499. );
  1500. OutputDebugString (Buffer);
  1501. }
  1502. #endif
  1503. DWORD
  1504. WINAPI
  1505. AddToMessageAlias(
  1506. PVOID params
  1507. )
  1508. /***************************************************************************\
  1509. * AddToMessageAlias
  1510. *
  1511. * History:
  1512. * 10-Apr-93 Robertre Created.
  1513. \***************************************************************************/
  1514. {
  1515. HANDLE hShellReadyEvent;
  1516. WCHAR UserName[MAX_PATH + 1];
  1517. DWORD UserNameLength = sizeof(UserName) / sizeof(*UserName);
  1518. DWORD dwCount;
  1519. BOOL standardShellWasStarted = *(BOOL *)params;
  1520. //
  1521. // Add the user's msg alias.
  1522. //
  1523. WriteLog(TEXT("Userinit: Adding MsgAlias"));
  1524. if (GetUserNameW(UserName, &UserNameLength)) {
  1525. AddMsgAlias(UserName);
  1526. } else {
  1527. UIPrint(("GetUserName failed, error = %d",GetLastError()));
  1528. }
  1529. WriteLog( TEXT("Userinit: Finished adding MsgAlias"));
  1530. if (standardShellWasStarted )
  1531. {
  1532. dwCount = 0;
  1533. while (TRUE) {
  1534. hShellReadyEvent = OpenEvent(EVENT_ALL_ACCESS,FALSE,L"ShellReadyEvent");
  1535. if (hShellReadyEvent == NULL)
  1536. {
  1537. if (GetLastError() == ERROR_FILE_NOT_FOUND) {
  1538. if (dwCount < 5) {
  1539. Sleep (3000);
  1540. dwCount++;
  1541. } else {
  1542. break;
  1543. }
  1544. } else {
  1545. break;
  1546. }
  1547. }
  1548. else
  1549. {
  1550. WaitForSingleObject(hShellReadyEvent, INFINITE);
  1551. Sleep(20000);
  1552. CloseHandle(hShellReadyEvent);
  1553. break;
  1554. }
  1555. }
  1556. }
  1557. SpoolerInit();
  1558. return( NO_ERROR );
  1559. }
  1560. BOOL
  1561. StartTheShell(
  1562. void
  1563. )
  1564. /***************************************************************************\
  1565. * StartTheShell
  1566. *
  1567. * Starts the shell, either explorer, the shell value specified in
  1568. * the registry for winlogon, or the alternate shell that is specified
  1569. * by the safeboot procedure.
  1570. *
  1571. * retrun
  1572. * TRUE if the standard shell was executed
  1573. * FALSE if a non-standard shell was executed.
  1574. *
  1575. * 14-Jan-98 WesW Created.
  1576. \***************************************************************************/
  1577. {
  1578. HKEY hKey;
  1579. DWORD dwSize, dwType;
  1580. WCHAR ShellCmdLine[MAX_PATH];
  1581. DWORD UseAlternateShell = 0;
  1582. HRESULT hr = S_OK;
  1583. //
  1584. // get the safeboot mode
  1585. //
  1586. if (RegOpenKeyEx(
  1587. HKEY_LOCAL_MACHINE,
  1588. TEXT("system\\currentcontrolset\\control\\safeboot\\option"),
  1589. 0,
  1590. KEY_READ,
  1591. &hKey
  1592. ) == ERROR_SUCCESS)
  1593. {
  1594. dwSize = sizeof(DWORD);
  1595. RegQueryValueEx (
  1596. hKey,
  1597. TEXT("UseAlternateShell"),
  1598. NULL,
  1599. &dwType,
  1600. (LPBYTE) &UseAlternateShell,
  1601. &dwSize
  1602. );
  1603. RegCloseKey( hKey );
  1604. if (UseAlternateShell) {
  1605. if (RegOpenKeyEx(
  1606. HKEY_LOCAL_MACHINE,
  1607. TEXT("system\\currentcontrolset\\control\\safeboot"),
  1608. 0,
  1609. KEY_READ,
  1610. &hKey
  1611. ) == ERROR_SUCCESS)
  1612. {
  1613. dwSize = sizeof(ShellCmdLine);
  1614. if (RegQueryValueEx (
  1615. hKey,
  1616. TEXT("AlternateShell"),
  1617. NULL,
  1618. &dwType,
  1619. (LPBYTE) ShellCmdLine,
  1620. &dwSize
  1621. ) != ERROR_SUCCESS || ShellCmdLine[0] == 0)
  1622. {
  1623. UseAlternateShell = 0;
  1624. }
  1625. RegCloseKey( hKey );
  1626. } else {
  1627. UseAlternateShell = 0;
  1628. }
  1629. }
  1630. }
  1631. //
  1632. // Before we start the shell, we must re-enable the shell's script
  1633. // zone security checks -- if we can't do this, it is not safe
  1634. // to start the shell since it may allow the user to run
  1635. // unsafe code without notification.
  1636. //
  1637. if ( ! EnableScriptZoneSecurityCheck() )
  1638. {
  1639. //
  1640. // We have to exit, and return TRUE which means that we failed to start
  1641. // the standard shell. We do this even if an alternate shell was desired since
  1642. // whenever the alternate shell fails to launch for some other reason,
  1643. // we try to launch explorer.exe and would return TRUE in that case.
  1644. //
  1645. return TRUE;
  1646. }
  1647. if (IsTSAppCompatOn()) {
  1648. if ( !ExecProcesses(TEXT("AppSetup"), NULL, FALSE, TRUE, TRUE ) ) {
  1649. ExecProcesses(TEXT("AppSetup"), NULL, TRUE, TRUE, TRUE);
  1650. }
  1651. }
  1652. if (UseAlternateShell) {
  1653. if (ExecApplication(ShellCmdLine, FALSE, FALSE, FALSE, SW_MAXIMIZE)) {
  1654. return FALSE; // an alt-shell was executed
  1655. }
  1656. } else if (NtCurrentPeb()->SessionId != 0) {
  1657. //
  1658. // Terminal Server: For remote sessions query the Terminal Server service
  1659. // to see if this session has specified a initial program other than
  1660. // explorer.exe.
  1661. //
  1662. BOOLEAN bExecOk = TRUE;
  1663. BOOLEAN IsWorkingDirWrong = FALSE;
  1664. UINT ErrorStringId;
  1665. LPTSTR psz = NULL;
  1666. LPTSTR pszerr = NULL;
  1667. ULONG Length;
  1668. BOOLEAN Result, fStartCtfmon = FALSE;
  1669. HANDLE dllHandle;
  1670. WCHAR szCtfmonPath[MAX_PATH];
  1671. DWORD cbSize;
  1672. //
  1673. // Load winsta.dll
  1674. //
  1675. dllHandle = LoadLibraryW(L"winsta.dll");
  1676. if (dllHandle) {
  1677. WINSTATIONCONFIG *pConfigData = LocalAlloc(LPTR, sizeof(WINSTATIONCONFIG));
  1678. if (pConfigData) {
  1679. PWINSTATION_QUERY_INFORMATION pfnWinstationQueryInformation;
  1680. pfnWinstationQueryInformation = (PWINSTATION_QUERY_INFORMATION) GetProcAddress(
  1681. dllHandle,
  1682. "WinStationQueryInformationW"
  1683. );
  1684. if (pfnWinstationQueryInformation) {
  1685. Result = pfnWinstationQueryInformation( SERVERNAME_CURRENT,
  1686. LOGONID_CURRENT,
  1687. WinStationConfiguration,
  1688. pConfigData,
  1689. sizeof(WINSTATIONCONFIG),
  1690. &Length );
  1691. if (Result && pConfigData->User.InitialProgram[0] ) {
  1692. //BUGID - 342176
  1693. if( !ExpandEnvironmentStrings( pConfigData->User.InitialProgram, ShellCmdLine, MAX_PATH ) )
  1694. {
  1695. hr = StringCchCopy( ShellCmdLine, MAX_PATH, pConfigData->User.InitialProgram );
  1696. if( FAILED(hr) ){
  1697. SetLastError(HRESULT_CODE(hr));
  1698. bExecOk = FALSE;
  1699. goto badexec;
  1700. }
  1701. }
  1702. //
  1703. // If a working directory is specified,
  1704. // then attempt to change the current directory to it.
  1705. //
  1706. if ( pConfigData->User.WorkDirectory[0] ) {
  1707. WCHAR WorkDirectory[ DIRECTORY_LENGTH + 1 ];
  1708. if ( !ExpandEnvironmentStrings( pConfigData->User.WorkDirectory, WorkDirectory, DIRECTORY_LENGTH + 1 ) ) {
  1709. hr = StringCchCopy( WorkDirectory, DIRECTORY_LENGTH + 1, pConfigData->User.WorkDirectory );
  1710. if( FAILED(hr) ){
  1711. SetLastError(HRESULT_CODE(hr));
  1712. bExecOk = FALSE;
  1713. goto badexec;
  1714. }
  1715. }
  1716. bExecOk = (BYTE) SetCurrentDirectory( WorkDirectory );
  1717. }
  1718. pszerr = pConfigData->User.WorkDirectory;
  1719. if ( !bExecOk ) {
  1720. DbgPrint( "USERINIT: Failed to set working directory %ws for SessionId %u\n",
  1721. pConfigData->User.WorkDirectory, NtCurrentPeb()->SessionId );
  1722. IsWorkingDirWrong = TRUE;
  1723. goto badexec;
  1724. } else {
  1725. //
  1726. // Also check the Registry and start ctfmon.exe
  1727. // This is so that, when we r in TS single application mode, langbar will appear for FE systems
  1728. //
  1729. cbSize = sizeof(szCtfmonPath);
  1730. fStartCtfmon = RegCheckCtfmon(szCtfmonPath, cbSize);
  1731. if (fStartCtfmon) {
  1732. WCHAR CtfmonCmdLine[MAX_PATH];
  1733. if( !ExpandEnvironmentStrings( szCtfmonPath, CtfmonCmdLine, MAX_PATH ) ) {
  1734. hr = StringCchCopy( CtfmonCmdLine, MAX_PATH, szCtfmonPath );
  1735. if( FAILED(hr) ) {
  1736. SetLastError(HRESULT_CODE(hr));
  1737. bExecOk = FALSE;
  1738. goto badexec;
  1739. }
  1740. }
  1741. bExecOk = (BYTE)ExecApplication( CtfmonCmdLine, FALSE, FALSE, FALSE, SW_SHOWNORMAL );
  1742. if (!bExecOk) {
  1743. // Ctfmon failed to start because of some reason
  1744. // Lets not fail - atleast we should try to start the Application
  1745. // This will fall back to the original behavior without langbar
  1746. DbgPrint("USERINIT: Failed to start ctfmon.exe in TS Single App mode ! \n");
  1747. }
  1748. }
  1749. }
  1750. bExecOk = (BYTE)ExecApplication( ShellCmdLine, FALSE, FALSE,
  1751. FALSE,(USHORT)(pConfigData->User.fMaximize ? SW_SHOWMAXIMIZED : SW_SHOW) );
  1752. pszerr = ShellCmdLine;
  1753. badexec:
  1754. if ( !bExecOk ) {
  1755. DWORD rc;
  1756. BOOL bGotString;
  1757. #define PSZ_MAX 256
  1758. WCHAR pszTemplate[PSZ_MAX];
  1759. LPTSTR errbuf = NULL;
  1760. rc = GetLastError();
  1761. FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM |
  1762. FORMAT_MESSAGE_ALLOCATE_BUFFER |
  1763. FORMAT_MESSAGE_MAX_WIDTH_MASK,
  1764. NULL,
  1765. rc,
  1766. 0,
  1767. (LPTSTR) (&psz),
  1768. 1,
  1769. NULL);
  1770. if (psz) {
  1771. if (IsWorkingDirWrong == TRUE)
  1772. {
  1773. ErrorStringId = IDS_FAILING_WORKINGDIR;
  1774. }
  1775. else
  1776. {
  1777. ErrorStringId = IDS_FAILING_SHELLCOMMAND;
  1778. }
  1779. bGotString = LoadString(NULL,ErrorStringId,pszTemplate,PSZ_MAX);
  1780. if (bGotString) {
  1781. errbuf = LocalAlloc(LPTR, 512 * sizeof(TCHAR));
  1782. if (errbuf) {
  1783. hr = StringCchPrintf( errbuf, 512, pszTemplate, psz, pszerr );
  1784. ASSERT(SUCCEEDED(hr));
  1785. }
  1786. }
  1787. LocalFree(psz);
  1788. }
  1789. else {
  1790. if (IsWorkingDirWrong == TRUE)
  1791. {
  1792. ErrorStringId = IDS_ERROR_WORKINGDIR;
  1793. }
  1794. else
  1795. {
  1796. ErrorStringId = IDS_ERROR_SHELLCOMMAND;
  1797. }
  1798. bGotString = LoadString(NULL,ErrorStringId,pszTemplate,PSZ_MAX);
  1799. if (bGotString) {
  1800. errbuf = LocalAlloc(LPTR, 512 * sizeof(WCHAR));
  1801. if (errbuf) {
  1802. hr = StringCchPrintf( errbuf, 512, pszTemplate, rc, pszerr );
  1803. ASSERT(SUCCEEDED(hr));
  1804. }
  1805. }
  1806. }
  1807. if (bGotString && errbuf) {
  1808. HelpMessageBox(NULL, NULL, errbuf, NULL, MB_OK | MB_ICONSTOP | MB_HELP, TEXT("MS-ITS:rdesktop.chm::/rdesktop_troubleshoot.htm"));
  1809. LocalFree(errbuf);
  1810. }
  1811. }
  1812. LocalFree(pConfigData);
  1813. FreeLibrary(dllHandle);
  1814. // an alt shell/program was executed
  1815. return FALSE ;
  1816. }
  1817. }
  1818. LocalFree(pConfigData);
  1819. } // if pConfigData
  1820. FreeLibrary(dllHandle);
  1821. }
  1822. }
  1823. if (!ExecProcesses(TEXT("shell"), NULL, FALSE, FALSE, FALSE)) {
  1824. ExecProcesses(TEXT("shell"), TEXT("explorer"), TRUE, FALSE, FALSE);
  1825. }
  1826. return TRUE; // standard shell/explorer was executed
  1827. }
  1828. VOID
  1829. DoAutoEnrollment(
  1830. LPTSTR Param
  1831. )
  1832. {
  1833. if (0==wcscmp(Param, AUTOENROLL_STARTUP)) {
  1834. AutoEnrollThread = CertAutoEnrollment( GetDesktopWindow(), CERT_AUTO_ENROLLMENT_START_UP );
  1835. } else {
  1836. AutoEnrollThread = CertAutoEnrollment( GetDesktopWindow(), CERT_AUTO_ENROLLMENT_WAKE_UP );
  1837. }
  1838. }
  1839. /***************************************************************************\
  1840. * WinMain
  1841. *
  1842. * History:
  1843. * 20-Aug-92 Davidc Created.
  1844. \***************************************************************************/
  1845. typedef BOOL (WINAPI * PFNIMMDISABLEIME)( DWORD );
  1846. int
  1847. WINAPI
  1848. WinMain(
  1849. HINSTANCE hInstance,
  1850. HINSTANCE hPrevInstance,
  1851. LPSTR lpszCmdParam,
  1852. int nCmdShow
  1853. )
  1854. {
  1855. LPTSTR lpLogonServer;
  1856. LPTSTR lpOriginalUNCLogonServer;
  1857. LPTSTR lpLogonScript;
  1858. LPTSTR lpMprLogonScripts;
  1859. LPTSTR lpGPOScriptType;
  1860. LPTSTR lpAutoEnroll;
  1861. LPTSTR lpAutoEnrollMode;
  1862. DWORD ThreadId;
  1863. DWORD WaitResult;
  1864. HANDLE ThreadHandle;
  1865. BOOL bRunLogonScriptsSync;
  1866. BOOL bRunGrpConv = FALSE;
  1867. HKEY hKey;
  1868. DWORD dwType, dwSize, dwTemp;
  1869. TCHAR szCmdLine[50];
  1870. BOOL standardShellWasStarted = FALSE;
  1871. HANDLE hImm = 0;
  1872. PFNIMMDISABLEIME pfnImmDisableIME = 0;
  1873. BOOL OptimizedLogon;
  1874. LPTSTR OptimizedLogonStatus;
  1875. HRESULT hr = S_OK;
  1876. WriteLog(TEXT("Userinit: Starting"));
  1877. if ( GetSystemMetrics( SM_IMMENABLED ) )
  1878. {
  1879. hImm = LoadLibrary( L"imm32.dll");
  1880. if ( hImm )
  1881. {
  1882. pfnImmDisableIME = (PFNIMMDISABLEIME) GetProcAddress( hImm,
  1883. "ImmDisableIME" );
  1884. if ( pfnImmDisableIME )
  1885. {
  1886. pfnImmDisableIME( -1 );
  1887. }
  1888. }
  1889. }
  1890. //
  1891. // Determine if we did an optimized logon. By default assume we did not.
  1892. //
  1893. OptimizedLogon = FALSE;
  1894. OptimizedLogonStatus = AllocAndGetEnvironmentVariable(OPTIMIZED_LOGON_VARIABLE);
  1895. if (OptimizedLogonStatus) {
  1896. if (lstrcmp(OptimizedLogonStatus, TEXT("1")) == 0) {
  1897. OptimizedLogon = TRUE;
  1898. }
  1899. Free(OptimizedLogonStatus);
  1900. }
  1901. SetEnvironmentVariable(OPTIMIZED_LOGON_VARIABLE, NULL);
  1902. //
  1903. // Check if userinit is being started to just run GPO scripts
  1904. //
  1905. lpGPOScriptType = AllocAndGetEnvironmentVariable(GPO_SCRIPT_TYPE_VARIABLE);
  1906. //
  1907. // Check if userinit.exe is being run just for auto enrollment
  1908. //
  1909. lpAutoEnroll = AllocAndGetEnvironmentVariable( AUTOENROLL_VARIABLE );
  1910. lpAutoEnrollMode = AllocAndGetEnvironmentVariable( AUTOENROLLMODE_VARIABLE );
  1911. SetEnvironmentVariable(AUTOENROLL_VARIABLE, NULL);
  1912. if (lpGPOScriptType) {
  1913. //
  1914. // Userinit was started to execute GPO scripts only
  1915. //
  1916. // Clean up the environment block
  1917. //
  1918. SetEnvironmentVariable(GPO_SCRIPT_TYPE_VARIABLE, NULL);
  1919. //
  1920. // Execute the scripts and clean up
  1921. //
  1922. RunGPOScripts (lpGPOScriptType);
  1923. Free(lpGPOScriptType);
  1924. //
  1925. // We're finished. Exit now.
  1926. //
  1927. if ( lpAutoEnroll == NULL )
  1928. {
  1929. goto Exit ;
  1930. }
  1931. }
  1932. if ( lpAutoEnroll )
  1933. {
  1934. if ( ( wcscmp( lpAutoEnroll, AUTOENROLL_NONEXCLUSIVE ) == 0 ) ||
  1935. ( wcscmp( lpAutoEnroll, AUTOENROLL_EXCLUSIVE ) == 0 ) )
  1936. {
  1937. if( lpAutoEnrollMode )
  1938. {
  1939. DoAutoEnrollment( lpAutoEnrollMode );
  1940. }
  1941. if ( wcscmp( lpAutoEnroll, AUTOENROLL_EXCLUSIVE ) == 0 )
  1942. {
  1943. goto Exit;
  1944. }
  1945. }
  1946. }
  1947. //
  1948. // Check if grpconv.exe needs to be run
  1949. //
  1950. if (RegOpenKeyEx (HKEY_CURRENT_USER, WINLOGON_KEY, 0,
  1951. KEY_READ, &hKey) == ERROR_SUCCESS) {
  1952. //
  1953. // Check for the sync flag.
  1954. //
  1955. dwSize = sizeof(bRunGrpConv);
  1956. if (ERROR_SUCCESS == RegQueryValueEx (hKey, GRPCONV_REG_VALUE_NAME, NULL, &dwType,
  1957. (LPBYTE) &bRunGrpConv, &dwSize))
  1958. {
  1959. if (REG_DWORD != dwType)
  1960. {
  1961. bRunGrpConv = FALSE; // Restore default
  1962. }
  1963. }
  1964. RegCloseKey (hKey);
  1965. }
  1966. //
  1967. // Run grpconv.exe if requested
  1968. //
  1969. if (bRunGrpConv) {
  1970. WriteLog(TEXT("Userinit: Running grpconv.exe"));
  1971. ExecApplication(g_szGrpConvExe, FALSE, TRUE, FALSE, SW_SHOWNORMAL);
  1972. }
  1973. //
  1974. // Get the logon script environment variables
  1975. //
  1976. lpLogonServer = AllocAndGetEnvironmentVariable(LOGON_SERVER_VARIABLE);
  1977. lpLogonScript = AllocAndGetEnvironmentVariable(LOGON_SCRIPT_VARIABLE);
  1978. lpMprLogonScripts = AllocAndGetEnvironmentMultiSz(MPR_LOGON_SCRIPT_VARIABLE);
  1979. //
  1980. // Delete the logon script environment variables
  1981. //
  1982. SetEnvironmentVariable(LOGON_SERVER_VARIABLE, NULL);
  1983. SetEnvironmentVariable(LOGON_SCRIPT_VARIABLE, NULL);
  1984. SetEnvironmentVariable(MPR_LOGON_SCRIPT_VARIABLE, NULL);
  1985. //
  1986. // See if logon scripts are to be run sync or async
  1987. //
  1988. bRunLogonScriptsSync = RunLogonScriptSync();
  1989. SetupHotKeyForKeyboardLayout();
  1990. //
  1991. // For application server see if we hve any .ini file/registry sync'ing to do
  1992. //We should do it before we start running logon scripts!
  1993. //
  1994. //First Check if Application compatibility is on
  1995. //
  1996. if (IsTSAppCompatOn())
  1997. {
  1998. HANDLE dllHandle;
  1999. if (lpMprLogonScripts) {
  2000. //Force to run logon script sync when a provider logon script exists when the system
  2001. //is a terminal server. This is because of the global flag on the registry
  2002. // doesn't work when two interactive users logon at the same time.
  2003. bRunLogonScriptsSync = TRUE;
  2004. }
  2005. //
  2006. // Load tsappcmp.dll
  2007. //
  2008. dllHandle = LoadLibrary (TEXT("tsappcmp.dll"));
  2009. if (dllHandle) {
  2010. PTERMSRCHECKNEWINIFILES pfnTermsrvCheckNewIniFiles;
  2011. pfnTermsrvCheckNewIniFiles = (PTERMSRCHECKNEWINIFILES) GetProcAddress(
  2012. dllHandle,
  2013. "TermsrvCheckNewIniFiles"
  2014. );
  2015. if (pfnTermsrvCheckNewIniFiles) {
  2016. pfnTermsrvCheckNewIniFiles();
  2017. }
  2018. FreeLibrary(dllHandle);
  2019. }
  2020. }
  2021. //
  2022. // If logon scripts can be run async then start the shell first.
  2023. //
  2024. if (bRunLogonScriptsSync) {
  2025. //
  2026. // Disable the shell's ie zone checking for the processes we
  2027. // are starting along with all their child processes
  2028. //
  2029. (void) DisableScriptZoneSecurityCheck();
  2030. RunLogonScript(lpLogonServer, lpLogonScript, bRunLogonScriptsSync, TRUE);
  2031. RunMprLogonScripts(lpMprLogonScripts, bRunLogonScriptsSync);
  2032. standardShellWasStarted = StartTheShell();
  2033. } else {
  2034. WriteLog(TEXT("Userinit: Starting the shell"));
  2035. standardShellWasStarted = StartTheShell();
  2036. (void) DisableScriptZoneSecurityCheck();
  2037. RunLogonScript(lpLogonServer, lpLogonScript, bRunLogonScriptsSync, TRUE);
  2038. RunMprLogonScripts(lpMprLogonScripts, bRunLogonScriptsSync);
  2039. }
  2040. UpdateUserSyncLogonScriptsCache(bRunLogonScriptsSync);
  2041. //
  2042. // Free up the buffers
  2043. //
  2044. Free(lpLogonServer);
  2045. Free(lpLogonScript);
  2046. Free(lpMprLogonScripts);
  2047. //
  2048. // Lower our priority so the shell can start faster
  2049. //
  2050. SetThreadPriority (GetCurrentThread(), THREAD_PRIORITY_LOWEST);
  2051. //
  2052. // Load remote fonts
  2053. //
  2054. LoadRemoteFonts();
  2055. //
  2056. // Initialize misc stuff
  2057. //
  2058. InitializeMisc (hInstance);
  2059. ThreadHandle = CreateThread(
  2060. NULL,
  2061. 0,
  2062. AddToMessageAlias,
  2063. &standardShellWasStarted,
  2064. 0,
  2065. &ThreadId
  2066. );
  2067. if (ThreadHandle)
  2068. {
  2069. WaitResult = WaitForSingleObject( ThreadHandle, TIMEOUT_VALUE );
  2070. if ( WaitResult == WAIT_TIMEOUT )
  2071. {
  2072. //
  2073. // This may never come back, so kill it.
  2074. //
  2075. UIPrint(("UserInit: AddToMessageAlias timeout, terminating thread\n"));
  2076. }
  2077. CloseHandle( ThreadHandle );
  2078. }
  2079. //
  2080. // If appropriate, start proquota.exe
  2081. //
  2082. if (RegOpenKeyEx (HKEY_CURRENT_USER, TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System"),
  2083. 0, KEY_READ, &hKey) == ERROR_SUCCESS) {
  2084. dwTemp = 0;
  2085. dwSize = sizeof(dwTemp);
  2086. if ((ERROR_SUCCESS == RegQueryValueEx (hKey, TEXT("EnableProfileQuota"), NULL, &dwType,
  2087. (LPBYTE) &dwTemp, &dwSize)) && (REG_DWORD == dwType)) {
  2088. if (dwTemp) {
  2089. hr = StringCchCopy (szCmdLine, 50, TEXT("proquota.exe"));
  2090. ASSERT(SUCCEEDED(hr));
  2091. ExecApplication(szCmdLine, FALSE, FALSE, FALSE, SW_SHOWNORMAL);
  2092. }
  2093. }
  2094. RegCloseKey (hKey);
  2095. }
  2096. Exit:
  2097. if ( AutoEnrollThread )
  2098. {
  2099. WaitResult = WaitForSingleObject( AutoEnrollThread, INFINITE );
  2100. CloseHandle( AutoEnrollThread );
  2101. AutoEnrollThread = NULL ;
  2102. }
  2103. Free(lpAutoEnroll);
  2104. Free(lpAutoEnrollMode);
  2105. if ( hImm )
  2106. {
  2107. FreeLibrary( hImm );
  2108. }
  2109. return(0);
  2110. }
  2111. //
  2112. // Determines if logon scripts should be executed sync or async
  2113. //
  2114. BOOL RunLogonScriptSync()
  2115. {
  2116. BOOL bSync = FALSE;
  2117. HKEY hKey;
  2118. DWORD dwType, dwSize;
  2119. //
  2120. // Check for a user preference
  2121. //
  2122. if (RegOpenKeyEx (HKEY_CURRENT_USER, WINLOGON_KEY, 0,
  2123. KEY_READ, &hKey) == ERROR_SUCCESS) {
  2124. //
  2125. // Check for the sync flag.
  2126. //
  2127. dwSize = sizeof(bSync);
  2128. RegQueryValueEx (hKey, SYNC_LOGON_SCRIPT, NULL, &dwType,
  2129. (LPBYTE) &bSync, &dwSize);
  2130. RegCloseKey (hKey);
  2131. }
  2132. //
  2133. // Check for a machine preference
  2134. //
  2135. if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, WINLOGON_KEY, 0,
  2136. KEY_READ, &hKey) == ERROR_SUCCESS) {
  2137. //
  2138. // Check for the sync flag.
  2139. //
  2140. dwSize = sizeof(bSync);
  2141. RegQueryValueEx (hKey, SYNC_LOGON_SCRIPT, NULL, &dwType,
  2142. (LPBYTE) &bSync, &dwSize);
  2143. RegCloseKey (hKey);
  2144. }
  2145. //
  2146. // Check for a user policy
  2147. //
  2148. if (RegOpenKeyEx (HKEY_CURRENT_USER, WINLOGON_POLICY_KEY, 0,
  2149. KEY_READ, &hKey) == ERROR_SUCCESS) {
  2150. //
  2151. // Check for the sync flag.
  2152. //
  2153. dwSize = sizeof(bSync);
  2154. RegQueryValueEx (hKey, SYNC_LOGON_SCRIPT, NULL, &dwType,
  2155. (LPBYTE) &bSync, &dwSize);
  2156. RegCloseKey (hKey);
  2157. }
  2158. //
  2159. // Check for a machine policy
  2160. //
  2161. if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, WINLOGON_POLICY_KEY, 0,
  2162. KEY_READ, &hKey) == ERROR_SUCCESS) {
  2163. //
  2164. // Check for the sync flag.
  2165. //
  2166. dwSize = sizeof(bSync);
  2167. RegQueryValueEx (hKey, SYNC_LOGON_SCRIPT, NULL, &dwType,
  2168. (LPBYTE) &bSync, &dwSize);
  2169. RegCloseKey (hKey);
  2170. }
  2171. return bSync;
  2172. }
  2173. //
  2174. // Determines if startup scripts should be executed sync or async
  2175. //
  2176. BOOL RunStartupScriptSync()
  2177. {
  2178. BOOL bSync = TRUE;
  2179. HKEY hKey;
  2180. DWORD dwType, dwSize;
  2181. //
  2182. // Check for a machine preference
  2183. //
  2184. if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, WINLOGON_KEY, 0,
  2185. KEY_READ, &hKey) == ERROR_SUCCESS) {
  2186. //
  2187. // Check for the sync flag.
  2188. //
  2189. dwSize = sizeof(bSync);
  2190. RegQueryValueEx (hKey, SYNC_STARTUP_SCRIPT, NULL, &dwType,
  2191. (LPBYTE) &bSync, &dwSize);
  2192. RegCloseKey (hKey);
  2193. }
  2194. //
  2195. // Check for a machine policy
  2196. //
  2197. if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, WINLOGON_POLICY_KEY, 0,
  2198. KEY_READ, &hKey) == ERROR_SUCCESS) {
  2199. //
  2200. // Check for the sync flag.
  2201. //
  2202. dwSize = sizeof(bSync);
  2203. RegQueryValueEx (hKey, SYNC_STARTUP_SCRIPT, NULL, &dwType,
  2204. (LPBYTE) &bSync, &dwSize);
  2205. RegCloseKey (hKey);
  2206. }
  2207. return bSync;
  2208. }
  2209. //
  2210. // Notify various components that a new user
  2211. // has logged into the workstation.
  2212. //
  2213. VOID
  2214. NewLogonNotify(
  2215. VOID
  2216. )
  2217. {
  2218. FARPROC lpProc;
  2219. HMODULE hLib;
  2220. HANDLE hEvent;
  2221. //
  2222. // Load the client-side user-mode PnP manager DLL
  2223. //
  2224. hLib = LoadLibrary(TEXT("setupapi.dll"));
  2225. if (hLib) {
  2226. lpProc = GetProcAddress(hLib, "CMP_Report_LogOn");
  2227. if (lpProc) {
  2228. //
  2229. // Ping the user-mode pnp manager -
  2230. // pass the private id as a parameter
  2231. //
  2232. (lpProc)(0x07020420, GetCurrentProcessId());
  2233. }
  2234. FreeLibrary(hLib);
  2235. }
  2236. //
  2237. // Notify DPAPI that a new user has just logged in. DPAPI will take
  2238. // this opportunity to re-synchronize its master keys if necessary.
  2239. //
  2240. {
  2241. BYTE BufferIn[8] = {0};
  2242. DATA_BLOB DataIn;
  2243. DATA_BLOB DataOut;
  2244. DataIn.pbData = BufferIn;
  2245. DataIn.cbData = sizeof(BufferIn);
  2246. CryptProtectData(&DataIn,
  2247. NULL,
  2248. NULL,
  2249. NULL,
  2250. NULL,
  2251. CRYPTPROTECT_CRED_SYNC,
  2252. &DataOut);
  2253. }
  2254. //
  2255. // Only do this for Console session
  2256. //
  2257. if ( NtCurrentPeb()->SessionId != 0 ) {
  2258. return;
  2259. }
  2260. //
  2261. // Notify RAS Autodial service that a new
  2262. // user has logged in.
  2263. //
  2264. hEvent = OpenEvent(SYNCHRONIZE|EVENT_MODIFY_STATE, FALSE, L"RasAutodialNewLogonUser");
  2265. if (hEvent) {
  2266. SetEvent(hEvent);
  2267. CloseHandle(hEvent);
  2268. }
  2269. }
  2270. BOOL SetupHotKeyForKeyboardLayout ()
  2271. {
  2272. if (!GetSystemMetrics(SM_REMOTESESSION)) {
  2273. //
  2274. // we dont care about local sessions.
  2275. //
  2276. return TRUE;
  2277. }
  2278. if (GetUserDefaultLangID() != LOWORD(GetKeyboardLayout(0))) {
  2279. //
  2280. // we are in a remote session, and we have different keyboard layouts for client and this users settings.
  2281. // the user should be allowed to switch the keyboard layout even if there is only 1 kbd layout available in his settings.
  2282. // since the current kbd layout is different that the one in his profile.
  2283. //
  2284. WCHAR szCtfmon[] = L"ctfmon.exe";
  2285. WCHAR szCtfmonCmd[] = L"ctfmon.exe /n";
  2286. HKEY hRunOnce;
  2287. DWORD dw;
  2288. //
  2289. // Lets put this in RunOnce.
  2290. //
  2291. if (RegCreateKeyEx(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Runonce",
  2292. 0, REG_NONE, REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE,
  2293. NULL, &hRunOnce, &dw) == ERROR_SUCCESS) {
  2294. WCHAR *szHotKeyReg = L"Keyboard Layout\\Toggle";
  2295. HKEY hHotKey;
  2296. WCHAR szHotKeylAltShft[] = L"1";
  2297. WCHAR szNoHotKey[] = L"3";
  2298. RegSetValueEx(hRunOnce, szCtfmon, 0, REG_SZ, (PBYTE)szCtfmonCmd, sizeof(szCtfmonCmd));
  2299. RegCloseKey(hRunOnce);
  2300. if (RegCreateKeyEx(HKEY_CURRENT_USER, szHotKeyReg, 0, REG_NONE, REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE,
  2301. NULL, &hHotKey, &dw) == ERROR_SUCCESS) {
  2302. DWORD dwType;
  2303. WCHAR szHotKey[3];
  2304. DWORD dwLen = sizeof(szHotKey);
  2305. BOOL bResetHotkey = FALSE;
  2306. if (RegQueryValueEx(hHotKey, L"Hotkey", NULL, &dwType,
  2307. (PBYTE)szHotKey, &dwLen) != ERROR_SUCCESS) {
  2308. bResetHotkey = TRUE;
  2309. }
  2310. if (bResetHotkey || !wcscmp(szHotKey, szNoHotKey))
  2311. {
  2312. //
  2313. // setup the registry for Hotkey.
  2314. //
  2315. if (RegSetValueEx(hHotKey, L"Hotkey", 0, REG_SZ,
  2316. (const BYTE *)szHotKeylAltShft, sizeof(szHotKeylAltShft)) == ERROR_SUCCESS) {
  2317. //
  2318. // now make call to read this registry and set the hotkey appropriately.
  2319. //
  2320. SystemParametersInfo( SPI_SETLANGTOGGLE, 0, NULL, 0);
  2321. }
  2322. }
  2323. RegCloseKey(hHotKey);
  2324. }
  2325. }
  2326. }
  2327. return TRUE;
  2328. }
  2329. /****************************************************************************
  2330. IsTSAppCompatOn()
  2331. Purpose:
  2332. Checks if TS application compatibility is enabled.
  2333. returns TRUE if enabled, FALSE - if not enabled or on case of error.
  2334. Comments:
  2335. This function goes to the registry only once.
  2336. All other times it just returnes the value.
  2337. ****************************************************************************/
  2338. BOOL
  2339. IsTSAppCompatOn()
  2340. {
  2341. static BOOL bAppCompatOn = FALSE;
  2342. static BOOL bFirst = TRUE;
  2343. if(bFirst)
  2344. {
  2345. HKEY hKey;
  2346. if( RegOpenKeyEx(HKEY_LOCAL_MACHINE, REG_CONTROL_TSERVER, 0,
  2347. KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS )
  2348. {
  2349. DWORD dwValue = 0;
  2350. DWORD dwType;
  2351. DWORD dwSize = sizeof(dwValue);
  2352. if( RegQueryValueEx(hKey, REG_TERMSRV_APPCOMPAT,
  2353. NULL, &dwType, (LPBYTE) &dwValue, &dwSize) == ERROR_SUCCESS )
  2354. {
  2355. bAppCompatOn = (dwValue != 0);
  2356. }
  2357. RegCloseKey(hKey);
  2358. }
  2359. bFirst = FALSE;
  2360. }
  2361. return bAppCompatOn;
  2362. }
  2363. /****************************************************************************
  2364. UpdateUserSyncLogonScriptsCache()
  2365. Purpose:
  2366. Update user's sync-logon-scripts setting cache in profile list.
  2367. ****************************************************************************/
  2368. VOID
  2369. UpdateUserSyncLogonScriptsCache(BOOL bSync)
  2370. {
  2371. HANDLE UserToken;
  2372. HKEY UserKey;
  2373. PWCHAR UserSidString;
  2374. PWCHAR KeyPath;
  2375. ULONG Length;
  2376. HRESULT hr = S_OK;
  2377. //
  2378. // Update user's sync-logon-scripts setting cache in profile list.
  2379. //
  2380. if (OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &UserToken)) {
  2381. UserSidString = GetSidString(UserToken);
  2382. if (UserSidString) {
  2383. Length = 0;
  2384. Length += wcslen(PROFILE_LIST_PATH);
  2385. Length += wcslen(L"\\");
  2386. Length += wcslen(UserSidString);
  2387. KeyPath = Alloc((Length + 1) * sizeof(WCHAR));
  2388. if (KeyPath) {
  2389. hr = StringCchCopy(KeyPath, Length + 1, PROFILE_LIST_PATH);
  2390. ASSERT(SUCCEEDED(hr));
  2391. hr = StringCchCat(KeyPath, Length + 1, L"\\");
  2392. ASSERT(SUCCEEDED(hr));
  2393. hr = StringCchCat(KeyPath, Length + 1, UserSidString);
  2394. ASSERT(SUCCEEDED(hr));
  2395. if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, KeyPath, 0,
  2396. KEY_SET_VALUE, &UserKey) == ERROR_SUCCESS) {
  2397. RegSetValueEx(UserKey, SYNC_LOGON_SCRIPT, 0, REG_DWORD,
  2398. (BYTE *) &bSync, sizeof(bSync));
  2399. RegCloseKey(UserKey);
  2400. }
  2401. Free(KeyPath);
  2402. }
  2403. DeleteSidString(UserSidString);
  2404. }
  2405. CloseHandle(UserToken);
  2406. }
  2407. return;
  2408. }
  2409. //
  2410. // RegCheckCtfMon - checks if the following reg key is present and returns the Application path present there
  2411. // HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run /ctfmon.exe
  2412. //
  2413. BOOLEAN
  2414. RegCheckCtfmon(PWCHAR szCtfmon, DWORD cbSize)
  2415. {
  2416. HKEY hCtfmon = NULL;
  2417. DWORD dwValueType;
  2418. DWORD dwError;
  2419. BOOLEAN bFound = FALSE;
  2420. dwError = RegOpenKeyEx(
  2421. HKEY_CURRENT_USER,
  2422. CTFMON_KEY,
  2423. 0,
  2424. KEY_QUERY_VALUE,
  2425. &hCtfmon
  2426. );
  2427. if (dwError != ERROR_SUCCESS) {
  2428. return bFound;
  2429. }
  2430. // Check to query the value under "ctfmon.exe" subkey
  2431. dwError = RegQueryValueEx(
  2432. hCtfmon,
  2433. REG_CTFMON,
  2434. NULL,
  2435. &dwValueType,
  2436. (LPBYTE)szCtfmon,
  2437. &cbSize // number of bytes in szCtfmon
  2438. );
  2439. if (ERROR_SUCCESS == dwError && dwValueType == REG_SZ) {
  2440. // Reg key is present
  2441. szCtfmon[MAX_PATH-1] = L'\0';
  2442. bFound = TRUE;
  2443. }
  2444. RegCloseKey(hCtfmon);
  2445. return bFound;
  2446. }