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.

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