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.

2249 lines
60 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1993.
  5. //
  6. // File: msgina.c
  7. //
  8. // Contents: Microsoft Logon GUI DLL
  9. //
  10. // History: 7-14-94 RichardW Created
  11. //
  12. //----------------------------------------------------------------------------
  13. #include "msgina.h"
  14. // Link Window
  15. #include "shlobj.h"
  16. #include "shlobjp.h"
  17. #ifdef _X86_
  18. #include "i386\oemhard.h"
  19. #endif
  20. #include <accctrl.h>
  21. #include <aclapi.h>
  22. HINSTANCE hDllInstance; // My instance, for resource loading
  23. HINSTANCE hAppInstance; // App instance, for dialogs, etc.
  24. PWLX_DISPATCH_VERSION_1_4 pWlxFuncs; // Ptr to table of functions
  25. PWLX_DISPATCH_VERSION_1_4 pTrueTable ; // Ptr to table in winlogon
  26. DWORD SafeBootMode;
  27. BOOL g_IsTerminalServer;
  28. BOOL g_Console = TRUE;
  29. BOOL VersionMismatch ;
  30. DWORD InterfaceVersion ;
  31. HKEY WinlogonKey ;
  32. int TSAuthenticatedLogon(PGLOBALS pGlobals);
  33. BOOL
  34. WINAPI
  35. DllMain(
  36. HINSTANCE hInstance,
  37. DWORD dwReason,
  38. LPVOID lpReserved)
  39. {
  40. switch (dwReason)
  41. {
  42. case DLL_PROCESS_ATTACH:
  43. DisableThreadLibraryCalls ( hInstance );
  44. hDllInstance = hInstance;
  45. g_IsTerminalServer = !!(USER_SHARED_DATA->SuiteMask & (1 << TerminalServer));
  46. #if DBG
  47. InitDebugSupport();
  48. #endif
  49. InitializeSecurityGlobals();
  50. #ifdef _X86_
  51. InitializeOEMId();
  52. #endif
  53. _Shell_DllMain(hInstance, dwReason);
  54. return(TRUE);
  55. case DLL_PROCESS_DETACH:
  56. _Shell_DllMain(hInstance, dwReason);
  57. FreeSecurityGlobals();
  58. return(TRUE);
  59. default:
  60. return(TRUE);
  61. }
  62. }
  63. BOOL
  64. WINAPI
  65. WlxNegotiate(
  66. DWORD dwWinlogonVersion,
  67. DWORD *pdwDllVersion
  68. )
  69. {
  70. InterfaceVersion = dwWinlogonVersion ;
  71. if (dwWinlogonVersion < WLX_CURRENT_VERSION)
  72. {
  73. DebugLog(( DEB_WARN, "Old WLX interface (%x)\n", dwWinlogonVersion ));
  74. if ( dwWinlogonVersion < WLX_VERSION_1_1 )
  75. {
  76. return FALSE ;
  77. }
  78. VersionMismatch = TRUE ;
  79. }
  80. *pdwDllVersion = WLX_CURRENT_VERSION;
  81. DebugLog((DEB_TRACE, "Negotiate: successful!\n"));
  82. return(TRUE);
  83. }
  84. BOOL GetDefaultCADSetting(void)
  85. {
  86. BOOL bDisableCad = FALSE;
  87. NT_PRODUCT_TYPE NtProductType;
  88. //
  89. // Servers and workstations in a domain will default to requiring CAD.
  90. // Workstations in a workgroup won't require CAD (by default). Note,
  91. // the default CAD setting can be overwritten by either a machine
  92. // preference or machine policy.
  93. //
  94. RtlGetNtProductType(&NtProductType);
  95. if ( IsWorkstation(NtProductType) )
  96. {
  97. if ( !IsMachineDomainMember() ) // This function is doing some caching
  98. { // so we don't need to be brighter here
  99. bDisableCad = TRUE;
  100. }
  101. }
  102. return bDisableCad;
  103. }
  104. BOOL GetDisableCad(PGLOBALS pGlobals)
  105. // Returns whether or not the user should be required to press C-A-D before
  106. // logging on. TRUE == Disable CAD, FALSE == Require CAD
  107. {
  108. DWORD dwSize;
  109. DWORD dwType;
  110. HKEY hKey;
  111. BOOL fDisableCad = GetDefaultCADSetting();
  112. dwSize = sizeof(fDisableCad);
  113. RegQueryValueEx (WinlogonKey, DISABLE_CAD, NULL, &dwType,
  114. (LPBYTE) &fDisableCad , &dwSize);
  115. //
  116. // Check if C+A+D is disabled via policy
  117. //
  118. if (RegOpenKeyEx( HKEY_LOCAL_MACHINE, WINLOGON_POLICY_KEY, 0, KEY_READ,
  119. &hKey) == ERROR_SUCCESS)
  120. {
  121. dwSize = sizeof(fDisableCad);
  122. RegQueryValueEx (hKey, DISABLE_CAD, NULL, &dwType,
  123. (LPBYTE) &fDisableCad , &dwSize);
  124. RegCloseKey (hKey);
  125. }
  126. //
  127. // if s/c is present, force on c-a-d, since that's the only way to tell the
  128. // difference
  129. //
  130. if ( g_Console )
  131. {
  132. ULONG_PTR Value ;
  133. pWlxFuncs->WlxGetOption( pGlobals->hGlobalWlx,
  134. WLX_OPTION_SMART_CARD_PRESENT,
  135. &Value);
  136. if ( Value )
  137. {
  138. fDisableCad = FALSE ;
  139. }
  140. }
  141. //
  142. // Check if C+A+D is disabled for remote Hydra clients and copy the client name
  143. //
  144. if (g_IsTerminalServer ) {
  145. HANDLE dllHandle;
  146. //
  147. // Load winsta.dll
  148. //
  149. dllHandle = LoadLibraryW(L"winsta.dll");
  150. if (dllHandle) {
  151. PWINSTATION_QUERY_INFORMATION pfnWinstationQueryInformation;
  152. pfnWinstationQueryInformation = (PWINSTATION_QUERY_INFORMATION) GetProcAddress(
  153. dllHandle,
  154. "WinStationQueryInformationW"
  155. );
  156. if (pfnWinstationQueryInformation) {
  157. WINSTATIONCLIENT ClientData;
  158. ULONG Length;
  159. //
  160. // Get the CAD disable data from the client
  161. //
  162. if ( pfnWinstationQueryInformation( SERVERNAME_CURRENT,
  163. LOGONID_CURRENT,
  164. WinStationClient,
  165. &ClientData,
  166. sizeof(ClientData),
  167. &Length ) ) {
  168. //
  169. // Take the client settings only if the CAD is not globally disabled for the server,
  170. // and, if this is not the console active session.
  171. //
  172. if (!fDisableCad && !IsActiveConsoleSession() )
  173. {
  174. fDisableCad = ClientData.fDisableCtrlAltDel;
  175. }
  176. //
  177. // Copy the Client Name, even console has a client name now, due to PTS and console disconnect features.
  178. //
  179. //
  180. lstrcpyn(pGlobals->MuGlobals.ClientName, ClientData.ClientName, CLIENTNAME_LENGTH);
  181. }
  182. else
  183. {
  184. if (!IsActiveConsoleSession()) {
  185. fDisableCad = TRUE;
  186. }
  187. // TS start could have been delayed until 60seconds post first console login.
  188. // Hence, it is safe to assume that this is the console session, besides,
  189. // we are initing some benign env var.
  190. lstrcpyn(pGlobals->MuGlobals.ClientName,L"Console", CLIENTNAME_LENGTH );
  191. }
  192. }
  193. FreeLibrary(dllHandle);
  194. }
  195. }
  196. // Friendly UI on -> ALWAYS disable CAD.
  197. if (ShellIsFriendlyUIActive())
  198. {
  199. fDisableCad = TRUE;
  200. }
  201. return fDisableCad;
  202. }
  203. BOOL
  204. MsGinaSetOption(
  205. HANDLE hWlx,
  206. DWORD Option,
  207. ULONG_PTR Value,
  208. ULONG_PTR * OldValue
  209. )
  210. {
  211. return FALSE ;
  212. }
  213. BOOL
  214. MsGinaGetOption(
  215. HANDLE hWlx,
  216. DWORD Option,
  217. ULONG_PTR * Value
  218. )
  219. {
  220. return FALSE ;
  221. }
  222. PWLX_DISPATCH_VERSION_1_4
  223. GetFixedUpTable(
  224. PVOID FakeTable
  225. )
  226. {
  227. int err ;
  228. PVOID p ;
  229. PWLX_DISPATCH_VERSION_1_4 pNewTable ;
  230. DWORD dwSize ;
  231. DWORD dwType ;
  232. pNewTable = LocalAlloc( LMEM_FIXED, sizeof( WLX_DISPATCH_VERSION_1_4 ) );
  233. if ( !pNewTable )
  234. {
  235. return NULL ;
  236. }
  237. dwSize = sizeof( PVOID );
  238. err = RegQueryValueEx(
  239. WinlogonKey,
  240. TEXT("Key"),
  241. NULL,
  242. &dwType,
  243. (PUCHAR) &p,
  244. &dwSize );
  245. if ( (err == 0) &&
  246. (dwType == REG_BINARY) &&
  247. (dwSize == sizeof( PVOID ) ) )
  248. {
  249. pTrueTable = p ;
  250. switch ( InterfaceVersion )
  251. {
  252. case WLX_VERSION_1_1:
  253. dwSize = sizeof( WLX_DISPATCH_VERSION_1_1 );
  254. break;
  255. case WLX_VERSION_1_2:
  256. case WLX_VERSION_1_3:
  257. case WLX_VERSION_1_4:
  258. dwSize = sizeof( WLX_DISPATCH_VERSION_1_2 );
  259. break;
  260. }
  261. RtlCopyMemory(
  262. pNewTable,
  263. FakeTable,
  264. dwSize );
  265. pNewTable->WlxGetOption = MsGinaGetOption ;
  266. pNewTable->WlxSetOption = MsGinaSetOption ;
  267. pNewTable->WlxCloseUserDesktop = pTrueTable->WlxCloseUserDesktop ;
  268. pNewTable->WlxWin31Migrate = pTrueTable->WlxWin31Migrate ;
  269. pNewTable->WlxQueryClientCredentials = pTrueTable->WlxQueryClientCredentials ;
  270. pNewTable->WlxQueryInetConnectorCredentials = pTrueTable->WlxQueryInetConnectorCredentials ;
  271. pNewTable->WlxDisconnect = pTrueTable->WlxDisconnect ;
  272. pNewTable->WlxQueryTerminalServicesData = pTrueTable->WlxQueryTerminalServicesData ;
  273. pNewTable->WlxQueryConsoleSwitchCredentials = pTrueTable->WlxQueryConsoleSwitchCredentials ;
  274. pNewTable->WlxQueryTsLogonCredentials = pTrueTable->WlxQueryTsLogonCredentials;
  275. }
  276. else
  277. {
  278. LocalFree( pNewTable );
  279. pNewTable = NULL ;
  280. }
  281. return pNewTable ;
  282. }
  283. extern DWORD g_dwMainThreadId; // declared in status.c (used to "fix" a thread safety issue)
  284. BOOL
  285. WINAPI
  286. WlxInitialize(
  287. LPWSTR lpWinsta,
  288. HANDLE hWlx,
  289. PVOID pvReserved,
  290. PVOID pWinlogonFunctions,
  291. PVOID *pWlxContext
  292. )
  293. {
  294. PGLOBALS pGlobals;
  295. HKEY hKey;
  296. DWORD dwSize, dwType;
  297. DWORD dwStringMemory;
  298. DWORD dwAutoLogonCount ;
  299. DWORD dwNoLockWksta ;
  300. // Upon which bitmaps should our text be painted.
  301. BOOL fTextOnLarge;
  302. BOOL fTextOnSmall;
  303. ULONG_PTR ProbeValue ;
  304. PWLX_GET_OPTION GetOptCall ;
  305. BOOL DoFixup ;
  306. BOOL DidFixup ;
  307. int err ;
  308. err = RegOpenKeyEx(
  309. HKEY_LOCAL_MACHINE,
  310. WINLOGON_KEY,
  311. 0,
  312. KEY_READ | KEY_WRITE,
  313. &WinlogonKey );
  314. if ( err != 0 )
  315. {
  316. return FALSE ;
  317. }
  318. DoFixup = TRUE ;
  319. DidFixup = FALSE ;
  320. if ( VersionMismatch )
  321. {
  322. pWlxFuncs = GetFixedUpTable( pWinlogonFunctions );
  323. if ( pWlxFuncs )
  324. {
  325. DidFixup = TRUE ;
  326. }
  327. else
  328. {
  329. pWlxFuncs = (PWLX_DISPATCH_VERSION_1_4) pWinlogonFunctions ;
  330. DidFixup = FALSE ;
  331. }
  332. }
  333. else
  334. {
  335. pWlxFuncs = (PWLX_DISPATCH_VERSION_1_4) pWinlogonFunctions ;
  336. }
  337. //
  338. // Probe the callback table to make sure we're ok:
  339. //
  340. try
  341. {
  342. GetOptCall = pWlxFuncs->WlxGetOption ;
  343. if ( GetOptCall( hWlx,
  344. WLX_OPTION_DISPATCH_TABLE_SIZE,
  345. &ProbeValue ) )
  346. {
  347. if ( ProbeValue == sizeof( WLX_DISPATCH_VERSION_1_4 ) )
  348. {
  349. DoFixup = FALSE ;
  350. }
  351. }
  352. }
  353. except ( EXCEPTION_EXECUTE_HANDLER )
  354. {
  355. NOTHING ;
  356. }
  357. if ( DoFixup && !DidFixup )
  358. {
  359. pWlxFuncs = GetFixedUpTable( pWinlogonFunctions );
  360. }
  361. if ( !pWlxFuncs )
  362. {
  363. return FALSE ;
  364. }
  365. pGlobals = LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, sizeof(GLOBALS));
  366. if ( !pGlobals )
  367. {
  368. return FALSE ;
  369. }
  370. if ( !NT_SUCCESS ( RtlInitializeCriticalSection( &pGlobals->csGlobals ) ) )
  371. {
  372. LocalFree( pGlobals );
  373. return FALSE ;
  374. }
  375. if ( !InitHKeyCurrentUserSupport() )
  376. {
  377. RtlDeleteCriticalSection( &pGlobals->csGlobals );
  378. LocalFree( pGlobals );
  379. return FALSE ;
  380. }
  381. // Reserve enough memory for 4 strings of length MAX_STRING_BYTES
  382. dwStringMemory = (MAX_STRING_BYTES * sizeof (WCHAR)) * 4;
  383. pGlobals->LockedMemory = VirtualAlloc(
  384. NULL,
  385. dwStringMemory,
  386. MEM_COMMIT,
  387. PAGE_READWRITE);
  388. if ( pGlobals->LockedMemory == NULL )
  389. {
  390. CleanupHKeyCurrentUserSupport();
  391. RtlDeleteCriticalSection( &pGlobals->csGlobals );
  392. LocalFree( pGlobals );
  393. return FALSE ;
  394. }
  395. VirtualLock( pGlobals->LockedMemory, dwStringMemory);
  396. memset( pGlobals->LockedMemory, 0, dwStringMemory );
  397. pGlobals->UserName = pGlobals->LockedMemory ;
  398. pGlobals->Domain = pGlobals->UserName + MAX_STRING_BYTES ;
  399. pGlobals->Password = pGlobals->Domain + MAX_STRING_BYTES ;
  400. pGlobals->OldPassword = pGlobals->Password + MAX_STRING_BYTES ;
  401. *pWlxContext = (PVOID) pGlobals;
  402. pGlobals->hGlobalWlx = hWlx;
  403. pWlxFuncs->WlxUseCtrlAltDel(hWlx);
  404. if ( DCacheInitialize() )
  405. {
  406. pGlobals->Cache = DCacheCreate();
  407. }
  408. else
  409. {
  410. pGlobals->Cache = NULL ;
  411. }
  412. if ( pGlobals->Cache == NULL )
  413. {
  414. CleanupHKeyCurrentUserSupport();
  415. RtlDeleteCriticalSection(&pGlobals->csGlobals);
  416. VirtualFree( pGlobals->LockedMemory, 0, MEM_RELEASE );
  417. LocalFree (pGlobals);
  418. DebugLog((DEB_ERROR, "Failed to init domain cache!\n"));
  419. return(FALSE);
  420. }
  421. dwSize = sizeof( dwNoLockWksta );
  422. if ( RegQueryValueEx(
  423. WinlogonKey,
  424. DISABLE_LOCK_WKSTA,
  425. 0,
  426. &dwType,
  427. (PUCHAR) &dwNoLockWksta,
  428. &dwSize ) == 0 )
  429. {
  430. if ( dwNoLockWksta == 2 )
  431. {
  432. dwNoLockWksta = 0 ;
  433. RegSetValueEx(
  434. WinlogonKey,
  435. DISABLE_LOCK_WKSTA,
  436. 0,
  437. REG_DWORD,
  438. (PUCHAR) &dwNoLockWksta,
  439. sizeof( DWORD ) );
  440. }
  441. }
  442. if (!InitializeAuthentication(pGlobals))
  443. {
  444. *pWlxContext = NULL;
  445. CleanupHKeyCurrentUserSupport();
  446. RtlDeleteCriticalSection(&pGlobals->csGlobals);
  447. VirtualFree( pGlobals->LockedMemory, 0, MEM_RELEASE );
  448. LocalFree (pGlobals);
  449. DebugLog((DEB_ERROR, "Failed to init authentication!\n"));
  450. return(FALSE);
  451. }
  452. //
  453. // Start by clearing the entire Multi-User Globals
  454. //
  455. RtlZeroMemory( &pGlobals->MuGlobals, sizeof(pGlobals->MuGlobals) );
  456. //
  457. // Get our SessionId and save in globals
  458. //
  459. pGlobals->MuGlobals.SessionId = NtCurrentPeb()->SessionId;
  460. if (pGlobals->MuGlobals.SessionId != 0) {
  461. g_Console = FALSE;
  462. }
  463. //
  464. // if this is a TS session, we can't run if there is a version
  465. // mismatch. Fail out now.
  466. //
  467. if ( (!g_Console) &&
  468. (VersionMismatch ) )
  469. {
  470. *pWlxContext = NULL;
  471. CleanupHKeyCurrentUserSupport();
  472. RtlDeleteCriticalSection(&pGlobals->csGlobals);
  473. LocalFree (pGlobals);
  474. DebugLog((DEB_ERROR, "Failed to init authentication!\n"));
  475. return(FALSE);
  476. }
  477. // Check if CAD is disabled
  478. GetDisableCad(pGlobals);
  479. //
  480. // If this is auto admin logon, or ctrl+alt+del is disabled,
  481. // generate a fake SAS right now. Don't attempt AutoLogon unless on Console
  482. //
  483. if ((g_Console && GetProfileInt( APPLICATION_NAME, TEXT("AutoAdminLogon"), 0) ) ||
  484. GetDisableCad(pGlobals))
  485. {
  486. dwSize = sizeof( DWORD );
  487. if ( RegQueryValueEx( WinlogonKey, AUTOLOGONCOUNT_KEY, NULL,
  488. &dwType, (LPBYTE) &dwAutoLogonCount,
  489. &dwSize ) == 0 )
  490. {
  491. //
  492. // AutoLogonCount value was present. Check the value:
  493. //
  494. if ( dwAutoLogonCount == 0 )
  495. {
  496. //
  497. // Went to zero. Reset everything:
  498. //
  499. RegDeleteValue( WinlogonKey, AUTOLOGONCOUNT_KEY );
  500. RegDeleteValue( WinlogonKey, DEFAULT_PASSWORD_KEY );
  501. RegSetValueEx( WinlogonKey, AUTOADMINLOGON_KEY, 0,
  502. REG_SZ, (LPBYTE) TEXT("0"), 2 * sizeof(WCHAR) );
  503. }
  504. else
  505. {
  506. //
  507. // Decrement the count, and try the logon:
  508. //
  509. dwAutoLogonCount-- ;
  510. RegSetValueEx( WinlogonKey, AUTOLOGONCOUNT_KEY,
  511. 0, REG_DWORD, (LPBYTE) &dwAutoLogonCount,
  512. sizeof( DWORD ) );
  513. KdPrint(( "AutoAdminLogon = 1\n" ));
  514. pWlxFuncs->WlxSasNotify(pGlobals->hGlobalWlx, WLX_SAS_TYPE_CTRL_ALT_DEL);
  515. }
  516. }
  517. else
  518. {
  519. //
  520. // AutoLogonCount not present
  521. //
  522. KdPrint(( "AutoAdminLogon = 1\n" ));
  523. pWlxFuncs->WlxSasNotify( pGlobals->hGlobalWlx, WLX_SAS_TYPE_CTRL_ALT_DEL );
  524. }
  525. }
  526. //
  527. // get the safeboot mode
  528. //
  529. if (RegOpenKeyEx(
  530. HKEY_LOCAL_MACHINE,
  531. TEXT("system\\currentcontrolset\\control\\safeboot\\option"),
  532. 0,
  533. KEY_READ,
  534. & hKey
  535. ) == ERROR_SUCCESS)
  536. {
  537. dwSize = sizeof(DWORD);
  538. RegQueryValueEx (
  539. hKey,
  540. TEXT("OptionValue"),
  541. NULL,
  542. &dwType,
  543. (LPBYTE) &SafeBootMode,
  544. &dwSize
  545. );
  546. RegCloseKey( hKey );
  547. }
  548. //
  549. // Load branding images
  550. //
  551. LoadBrandingImages(FALSE, &fTextOnLarge, &fTextOnSmall);
  552. //
  553. // Create fonts
  554. //
  555. CreateFonts(&pGlobals->GinaFonts);
  556. //
  557. // Draw localized text on branding images
  558. //
  559. PaintBitmapText(&pGlobals->GinaFonts, fTextOnLarge, fTextOnSmall);
  560. //
  561. // Initialize consumer windows changes
  562. //
  563. _Shell_Initialize(pGlobals);
  564. //
  565. // Initialize this global that's used in status.c. We know that WlxInitialize is called
  566. // on the main thread of winlogon.
  567. //
  568. g_dwMainThreadId = GetCurrentThreadId();
  569. return(TRUE);
  570. }
  571. VOID
  572. WINAPI
  573. WlxDisplaySASNotice(PVOID pContext)
  574. {
  575. PGLOBALS pGlobals = (PGLOBALS)pContext;
  576. INITCOMMONCONTROLSEX icce;
  577. icce.dwSize = sizeof (icce);
  578. icce.dwICC = ICC_ANIMATE_CLASS;
  579. InitCommonControlsEx(&icce);
  580. // Need to register the link window
  581. LinkWindow_RegisterClass();
  582. pWlxFuncs->WlxDialogBoxParam( pGlobals->hGlobalWlx,
  583. hDllInstance,
  584. (LPTSTR) IDD_WELCOME_DIALOG,
  585. NULL,
  586. WelcomeDlgProc,
  587. (LPARAM) pContext );
  588. }
  589. PWSTR
  590. AllocAndExpandProfilePath(
  591. PGLOBALS pGlobals,
  592. LPWSTR lpUserName)
  593. {
  594. WCHAR szPath[MAX_PATH];
  595. WCHAR szFullPath[MAX_PATH];
  596. WCHAR szServerName[UNCLEN];
  597. WCHAR szUserName[100];
  598. DWORD cFullPath;
  599. PWSTR pszFullPath;
  600. DWORD dwPathLen=0;
  601. //
  602. // Set up the logon server environment variable:
  603. //
  604. szServerName[0] = L'\\';
  605. szServerName[1] = L'\\';
  606. CopyMemory( &szServerName[2],
  607. pGlobals->Profile->LogonServer.Buffer,
  608. pGlobals->Profile->LogonServer.Length );
  609. szServerName[pGlobals->Profile->LogonServer.Length / sizeof(WCHAR) + 2] = L'\0';
  610. SetEnvironmentVariable(LOGONSERVER_VARIABLE, szServerName);
  611. dwPathLen = lstrlen(pGlobals->MuGlobals.TSData.ProfilePath);
  612. if (!g_Console && (dwPathLen > 0)) {
  613. //
  614. // See if the user specified a Terminal Server profile path.
  615. // If so, we override the regular profile path
  616. //
  617. if (dwPathLen < MAX_PATH)
  618. {
  619. lstrcpy(szPath, pGlobals->MuGlobals.TSData.ProfilePath);
  620. }
  621. else
  622. {
  623. lstrcpy(szPath, NULL_STRING);
  624. }
  625. } else {
  626. dwPathLen = pGlobals->Profile->ProfilePath.Length;
  627. if (dwPathLen == 0)
  628. {
  629. return(NULL);
  630. }
  631. //
  632. // Copy the profile path locally
  633. //
  634. if (dwPathLen <= (MAX_PATH-1)*sizeof(WCHAR))
  635. {
  636. CopyMemory( szPath,
  637. pGlobals->Profile->ProfilePath.Buffer,
  638. dwPathLen);
  639. szPath[dwPathLen / sizeof(WCHAR)] = L'\0';
  640. }
  641. else
  642. {
  643. lstrcpy(szPath, NULL_STRING);
  644. }
  645. }
  646. if (lpUserName && *lpUserName) {
  647. szUserName[0] = TEXT('\0');
  648. GetEnvironmentVariableW (USERNAME_VARIABLE, szUserName, 100);
  649. SetEnvironmentVariableW (USERNAME_VARIABLE, lpUserName);
  650. }
  651. //
  652. // Expand the profile path using current settings:
  653. //
  654. cFullPath = ExpandEnvironmentStrings(szPath, szFullPath, MAX_PATH);
  655. if (cFullPath)
  656. {
  657. pszFullPath = LocalAlloc(LMEM_FIXED, cFullPath * sizeof(WCHAR));
  658. if (pszFullPath)
  659. {
  660. CopyMemory( pszFullPath, szFullPath, cFullPath * sizeof(WCHAR));
  661. }
  662. }
  663. else
  664. {
  665. pszFullPath = NULL;
  666. }
  667. if (lpUserName && *lpUserName) {
  668. if (szUserName[0] != TEXT('\0'))
  669. SetEnvironmentVariableW (USERNAME_VARIABLE, szUserName);
  670. else
  671. SetEnvironmentVariableW (USERNAME_VARIABLE, NULL);
  672. }
  673. return(pszFullPath);
  674. }
  675. PWSTR
  676. AllocPolicyPath(
  677. PGLOBALS pGlobals)
  678. {
  679. LPWSTR pszPath;
  680. pszPath = LocalAlloc(LPTR, MAX_PATH * sizeof(WCHAR));
  681. if ( pszPath )
  682. {
  683. pszPath[0] = L'\\';
  684. pszPath[1] = L'\\';
  685. CopyMemory( &pszPath[2],
  686. pGlobals->Profile->LogonServer.Buffer,
  687. pGlobals->Profile->LogonServer.Length );
  688. wcscpy( &pszPath[ pGlobals->Profile->LogonServer.Length / sizeof(WCHAR) + 2],
  689. L"\\netlogon\\ntconfig.pol" );
  690. }
  691. return(pszPath);
  692. }
  693. PWSTR
  694. AllocNetDefUserProfilePath(
  695. PGLOBALS pGlobals)
  696. {
  697. LPWSTR pszPath;
  698. pszPath = LocalAlloc(LPTR, MAX_PATH * sizeof(WCHAR));
  699. if ( pszPath )
  700. {
  701. //
  702. // Set up the logon server environment variable:
  703. //
  704. pszPath[0] = L'\\';
  705. pszPath[1] = L'\\';
  706. CopyMemory( &pszPath[2],
  707. pGlobals->Profile->LogonServer.Buffer,
  708. pGlobals->Profile->LogonServer.Length );
  709. wcscpy( &pszPath[ pGlobals->Profile->LogonServer.Length / sizeof(WCHAR) + 2],
  710. L"\\netlogon\\Default User" );
  711. }
  712. return(pszPath);
  713. }
  714. PWSTR
  715. AllocServerName(
  716. PGLOBALS pGlobals)
  717. {
  718. LPWSTR pszPath;
  719. pszPath = LocalAlloc(LPTR, MAX_PATH * sizeof(WCHAR));
  720. if ( pszPath )
  721. {
  722. //
  723. // Set up the logon server environment variable:
  724. //
  725. pszPath[0] = L'\\';
  726. pszPath[1] = L'\\';
  727. CopyMemory( &pszPath[2],
  728. pGlobals->Profile->LogonServer.Buffer,
  729. pGlobals->Profile->LogonServer.Length );
  730. pszPath[pGlobals->Profile->LogonServer.Length / sizeof(WCHAR) + 2] = L'\0';
  731. }
  732. return(pszPath);
  733. }
  734. VOID
  735. DetermineDnsDomain(
  736. PGLOBALS pGlobals
  737. )
  738. {
  739. DWORD dwError = ERROR_SUCCESS;
  740. LPTSTR lpUserName = NULL, lpTemp;
  741. ULONG ulUserNameSize;
  742. pGlobals->DnsDomain = NULL;
  743. if ( ImpersonateLoggedOnUser( pGlobals->UserProcessData.UserToken ) )
  744. {
  745. ulUserNameSize = 75; // Pick a default size. We'll expand if necessary
  746. lpUserName = LocalAlloc (LPTR, ulUserNameSize * sizeof(TCHAR));
  747. if (!lpUserName)
  748. {
  749. dwError = GetLastError();
  750. }
  751. else
  752. {
  753. DWORD dwCount = 0;
  754. while (TRUE)
  755. {
  756. if (GetUserNameEx (NameDnsDomain, lpUserName, &ulUserNameSize))
  757. {
  758. dwError = ERROR_SUCCESS;
  759. break;
  760. }
  761. else
  762. {
  763. dwError = GetLastError();
  764. //
  765. // If the call failed due to insufficient memory, realloc
  766. // the buffer and try again.
  767. //
  768. if ((dwError == ERROR_INSUFFICIENT_BUFFER) || (dwError == ERROR_MORE_DATA))
  769. {
  770. LocalFree(lpUserName);
  771. lpUserName = LocalAlloc (LPTR, ulUserNameSize * sizeof(TCHAR));
  772. if (!lpUserName) {
  773. dwError = GetLastError();
  774. break; // Can't recover
  775. }
  776. }
  777. else if (dwError == ERROR_NO_SUCH_DOMAIN)
  778. {
  779. // We just logged on so we know that the domain exists
  780. // This is what happens with NT4 domain though since we try
  781. // to query the DNS domain name and it doesn't exists
  782. // Let's fall back to our old logic
  783. break;
  784. }
  785. else if (dwError == ERROR_NONE_MAPPED)
  786. {
  787. // That's what's returned for local users.
  788. break;
  789. }
  790. else
  791. {
  792. dwCount++;
  793. if (dwCount > 3)
  794. {
  795. break;
  796. }
  797. }
  798. }
  799. }
  800. }
  801. RevertToSelf();
  802. }
  803. else
  804. {
  805. dwError = GetLastError();
  806. }
  807. if (dwError == ERROR_SUCCESS)
  808. {
  809. //
  810. // At this point lpUserName contains something like domain.company.com\someuser
  811. // We are only interested in the dns domain name
  812. lpTemp = lpUserName;
  813. while (*lpTemp && ((*lpTemp) != TEXT('\\')))
  814. lpTemp++;
  815. if (*lpTemp != TEXT('\\'))
  816. {
  817. DebugLog((DEB_ERROR, "DetermineDnsDomain: Failed to find slash in DNS style name\n"));
  818. dwError = ERROR_INVALID_DATA;
  819. }
  820. else
  821. {
  822. *lpTemp = TEXT('\0');
  823. pGlobals->DnsDomain = DupString(lpUserName);
  824. }
  825. }
  826. if (dwError != ERROR_SUCCESS)
  827. {
  828. //
  829. // If GetUserNameEx didn't yield a DNS name, fall back on the old code.
  830. //
  831. PDOMAIN_CACHE_ENTRY Entry ;
  832. Entry = DCacheLocateEntry(
  833. pGlobals->Cache,
  834. pGlobals->FlatDomain.Buffer );
  835. if ( Entry )
  836. {
  837. if ( Entry->Type == DomainNt5 )
  838. {
  839. pGlobals->DnsDomain = DupString( Entry->DnsName.Buffer );
  840. }
  841. else
  842. {
  843. //
  844. // For all intended purposes, this is good enough.
  845. // winlogon needs to know for sure for policy (419926)
  846. //
  847. pGlobals->DnsDomain = DupString( L"\\NT4" );
  848. }
  849. DCacheDereferenceEntry( Entry );
  850. }
  851. else
  852. {
  853. //
  854. // winlogon needs to know this as well. errors and not-found
  855. // were assumed NT5
  856. //
  857. pGlobals->DnsDomain = DupString( L"\\XFOREST" );
  858. }
  859. }
  860. if (lpUserName)
  861. {
  862. LocalFree(lpUserName);
  863. }
  864. //
  865. // Don't leave with pGlobals->DnsDomain set to NULL
  866. //
  867. if ( pGlobals->DnsDomain == NULL)
  868. {
  869. pGlobals->DnsDomain = DupString( L"" );
  870. }
  871. }
  872. PWSTR
  873. AllocVolatileEnvironment(
  874. PGLOBALS pGlobals)
  875. {
  876. BOOL DeepShare;
  877. LPWSTR pszEnv;
  878. DWORD dwSize;
  879. TCHAR lpHomeShare[MAX_PATH] = TEXT("");
  880. TCHAR lpHomePath[MAX_PATH] = TEXT("");
  881. TCHAR lpHomeDrive[4] = TEXT("");
  882. TCHAR lpHomeDirectory[MAX_PATH] = TEXT("");
  883. BOOL TSHomeDir = FALSE;
  884. PVOID lpEnvironment = NULL; // Dummy environment
  885. //
  886. // Set the home directory environment variables
  887. // in a dummy environment block
  888. //
  889. if ( !g_Console ) {
  890. // See if the user specified a TerminalServer Home Directory.
  891. // If so, we override the regular directory
  892. if (lstrlen(pGlobals->MuGlobals.TSData.HomeDir) > 0) {
  893. lstrcpy(lpHomeDirectory, pGlobals->MuGlobals.TSData.HomeDir);
  894. TSHomeDir = TRUE;
  895. }
  896. if (lstrlen(pGlobals->MuGlobals.TSData.HomeDirDrive) > 0) {
  897. lstrcpy(lpHomeDrive, pGlobals->MuGlobals.TSData.HomeDirDrive);
  898. TSHomeDir = TRUE;
  899. }
  900. }
  901. if (!TSHomeDir) {
  902. if (pGlobals->Profile->HomeDirectoryDrive.Length &&
  903. (pGlobals->Profile->HomeDirectoryDrive.Length + 1) < (MAX_PATH*sizeof(TCHAR))) {
  904. lstrcpy(lpHomeDrive, pGlobals->Profile->HomeDirectoryDrive.Buffer);
  905. }
  906. if (pGlobals->Profile->HomeDirectory.Length &&
  907. (pGlobals->Profile->HomeDirectory.Length + 1) < (MAX_PATH*sizeof(TCHAR))) {
  908. lstrcpy(lpHomeDirectory, pGlobals->Profile->HomeDirectory.Buffer);
  909. }
  910. }
  911. //
  912. // Note : we are passing in a null environment because here we are only
  913. // interested in parsing the homedirectory and set it in the volatile
  914. // environment. We are not interested in setting it in the
  915. // environment block here.
  916. //
  917. // Also over here, we are only interested in setting up the
  918. // HOMESHARE and HOMEPATH variables in such a way that
  919. // %HOMESHARE%%HOMEPATH% points to the homedir. This is done
  920. // so that when folder redirection calls SHGetFolderPath, it will be
  921. // able to expand the paths properly. Therefore, at this point
  922. // it is not really necessary to pay attention to the
  923. // ConnectHomeDirToRoot policy because that policy might get changed
  924. // during policy processing anyway and will be picked up when the
  925. // shell starts up. Note: the values of HOMESHARE, HOMEPATH and
  926. // HOMEDRIVE will be updated correctly when the shell starts up
  927. //
  928. // At this point we do not map the home directory for 2 reasons:
  929. // (a) We are not aware of the ConnectHomeDirToRoot setting here.
  930. // (b) We do not want to do the network mapping twice : once here
  931. // and once when the shell starts up.
  932. //
  933. SetHomeDirectoryEnvVars(&lpEnvironment,
  934. lpHomeDirectory,
  935. lpHomeDrive,
  936. lpHomeShare,
  937. lpHomePath,
  938. &DeepShare);
  939. if ( pGlobals->DnsDomain == NULL )
  940. {
  941. DetermineDnsDomain( pGlobals );
  942. }
  943. dwSize = lstrlen (LOGONSERVER_VARIABLE) + 3
  944. + lstrlen (pGlobals->Profile->LogonServer.Buffer) + 3;
  945. if (L'\0' == lpHomeShare[0])
  946. {
  947. // Set the homedrive variable only if the home directory is not
  948. // a UNC path
  949. dwSize += lstrlen (HOMEDRIVE_VARIABLE) + 1 + lstrlen (lpHomeDrive) + 3;
  950. }
  951. else
  952. {
  953. // Set the homeshare variable only if the home directory is a UNC path
  954. dwSize += lstrlen (HOMESHARE_VARIABLE) + 1 + lstrlen (lpHomeShare) + 3;
  955. }
  956. dwSize += lstrlen (HOMEPATH_VARIABLE) + 1 + lstrlen (lpHomePath) + 3;
  957. if ( pGlobals->DnsDomain )
  958. {
  959. dwSize += (lstrlen( USERDNSDOMAIN_VARIABLE ) + 3 +
  960. lstrlen( pGlobals->DnsDomain ) + 3 );
  961. }
  962. if (g_IsTerminalServer) {
  963. dwSize += lstrlen (CLIENTNAME_VARIABLE) + 1 + lstrlen (pGlobals->MuGlobals.ClientName) + 3;
  964. }
  965. pszEnv = LocalAlloc(LPTR, dwSize * sizeof(WCHAR));
  966. if ( pszEnv )
  967. {
  968. LPWSTR pszEnvTmp;
  969. lstrcpy (pszEnv, LOGONSERVER_VARIABLE);
  970. lstrcat (pszEnv, L"=\\\\");
  971. lstrcat (pszEnv, pGlobals->Profile->LogonServer.Buffer);
  972. pszEnvTmp = pszEnv + (lstrlen( pszEnv ) + 1);
  973. if (L'\0' == lpHomeShare[0])
  974. {
  975. // Set the homedrive variable only if it is not a UNC path
  976. lstrcpy (pszEnvTmp, HOMEDRIVE_VARIABLE);
  977. lstrcat (pszEnvTmp, L"=");
  978. lstrcat (pszEnvTmp, lpHomeDrive);
  979. pszEnvTmp += (lstrlen(pszEnvTmp) + 1);
  980. }
  981. else
  982. {
  983. // Set the homeshare variable only if it is a UNC path
  984. lstrcpy (pszEnvTmp, HOMESHARE_VARIABLE);
  985. lstrcat (pszEnvTmp, L"=");
  986. lstrcat (pszEnvTmp, lpHomeShare);
  987. pszEnvTmp += (lstrlen(pszEnvTmp) + 1);
  988. }
  989. // Set the homepath variable
  990. lstrcpy (pszEnvTmp, HOMEPATH_VARIABLE);
  991. lstrcat (pszEnvTmp, L"=");
  992. lstrcat (pszEnvTmp, lpHomePath);
  993. pszEnvTmp += (lstrlen(pszEnvTmp) + 1);
  994. if (( pGlobals->DnsDomain ) && (*(pGlobals->DnsDomain)))
  995. {
  996. lstrcpy( pszEnvTmp, USERDNSDOMAIN_VARIABLE );
  997. lstrcat( pszEnvTmp, L"=" );
  998. lstrcat( pszEnvTmp, pGlobals->DnsDomain );
  999. pszEnvTmp += (lstrlen( pszEnvTmp ) + 1 );
  1000. }
  1001. if (g_IsTerminalServer) {
  1002. lstrcpy (pszEnvTmp, CLIENTNAME_VARIABLE);
  1003. lstrcat (pszEnvTmp, L"=");
  1004. lstrcat (pszEnvTmp, pGlobals->MuGlobals.ClientName);
  1005. pszEnvTmp += (lstrlen( pszEnvTmp ) + 1 );
  1006. }
  1007. *pszEnvTmp++ = L'\0';
  1008. }
  1009. return(pszEnv);
  1010. }
  1011. BOOL
  1012. ForceAutoLogon(
  1013. VOID
  1014. )
  1015. {
  1016. HKEY hkey;
  1017. BOOL fForceKeySet = FALSE;
  1018. BOOL fHaveAutoLogonCount = FALSE;
  1019. if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, WINLOGON_KEY, 0, KEY_READ, &hkey))
  1020. {
  1021. DWORD dwValue;
  1022. DWORD dwType;
  1023. DWORD dwSize = sizeof (dwValue);
  1024. if (ERROR_SUCCESS == RegQueryValueEx(hkey,
  1025. AUTOLOGONCOUNT_KEY,
  1026. NULL,
  1027. &dwType,
  1028. (LPBYTE) &dwValue,
  1029. &dwSize ))
  1030. {
  1031. fHaveAutoLogonCount = TRUE;
  1032. }
  1033. dwSize = sizeof (dwValue);
  1034. if (ERROR_SUCCESS == RegQueryValueEx(hkey,
  1035. FORCEAUTOLOGON_KEY,
  1036. NULL,
  1037. &dwType,
  1038. (LPBYTE) &dwValue,
  1039. &dwSize ))
  1040. {
  1041. //
  1042. // Check the value as a REG_SZ since all the other autologon values
  1043. // are stored as REG_SZs. Check it as a REG_DWORD for back-compat.
  1044. //
  1045. if (dwType == REG_DWORD)
  1046. {
  1047. if (0 != dwValue)
  1048. {
  1049. fForceKeySet = TRUE;
  1050. }
  1051. }
  1052. else if (dwType == REG_SZ)
  1053. {
  1054. //
  1055. // Reread the value for consistency with the way other
  1056. // autologon values are read/checked.
  1057. //
  1058. if (GetProfileInt(APPLICATION_NAME, FORCEAUTOLOGON_KEY, 0) != 0)
  1059. {
  1060. fForceKeySet = TRUE;
  1061. }
  1062. }
  1063. }
  1064. RegCloseKey(hkey);
  1065. }
  1066. return (fHaveAutoLogonCount || fForceKeySet);
  1067. }
  1068. /****************************************************************************\
  1069. *
  1070. * FUNCTION: CreateFolderAndACLit_Worker
  1071. *
  1072. * PURPOSE: Create a home-dir folder for the user, and set the proper security
  1073. * such that only the user and the admin have access to the folder.
  1074. *
  1075. * PARAMS: [in ] szPath the full path, could be UNC or local
  1076. * [in ] pUserSID user SID
  1077. * [out] pdwErr error code if anything fails.
  1078. *
  1079. * RETURNS: TRUE if all went ok
  1080. * FALSE if a bad home dir path was specified.
  1081. *
  1082. * HISTORY:
  1083. * TsUserEX ( Alhen's code which was based on EricB's DSPROP_CreateHomeDirectory )
  1084. *
  1085. *
  1086. \****************************************************************************/
  1087. #define ACE_COUNT 2
  1088. BOOLEAN CreateFolderAndACLit_Worker ( PWCHAR szPath , PSID pUserSID, PDWORD pdwErr , BOOLEAN pathIsLocal )
  1089. {
  1090. SECURITY_ATTRIBUTES securityAttributes;
  1091. BOOLEAN rc;
  1092. PSID psidAdmins = NULL;
  1093. *pdwErr = 0;
  1094. ZeroMemory( &securityAttributes , sizeof( SECURITY_ATTRIBUTES ) );
  1095. if ( !pathIsLocal )
  1096. {
  1097. // build a DACL
  1098. PSID pAceSid[ACE_COUNT];
  1099. PACL pDacl;
  1100. SID_IDENTIFIER_AUTHORITY NtAuth = SECURITY_NT_AUTHORITY;
  1101. SECURITY_DESCRIPTOR securityDescriptor;
  1102. PSECURITY_DESCRIPTOR pSecurityDescriptor = &securityDescriptor;
  1103. int i;
  1104. EXPLICIT_ACCESS rgAccessEntry[ACE_COUNT] = {0};
  1105. OBJECTS_AND_SID rgObjectsAndSid[ACE_COUNT] = {0};
  1106. if (!AllocateAndInitializeSid(&NtAuth,
  1107. 2,
  1108. SECURITY_BUILTIN_DOMAIN_RID,
  1109. DOMAIN_ALIAS_RID_ADMINS,
  1110. 0, 0, 0, 0, 0, 0,
  1111. &psidAdmins ) )
  1112. {
  1113. DebugLog(( DEB_ERROR, "AllocateAndInitializeSid failed\n" ));
  1114. *pdwErr = GetLastError( );
  1115. rc=FALSE;
  1116. goto done;
  1117. }
  1118. pAceSid[0] = pUserSID;
  1119. pAceSid[1] = psidAdmins;
  1120. for ( i = 0 ; i < ACE_COUNT; i++)
  1121. {
  1122. rgAccessEntry[i].grfAccessPermissions = GENERIC_ALL;
  1123. rgAccessEntry[i].grfAccessMode = GRANT_ACCESS;
  1124. rgAccessEntry[i].grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT;
  1125. // build the trustee structs
  1126. //
  1127. BuildTrusteeWithObjectsAndSid(&(rgAccessEntry[i].Trustee),
  1128. &(rgObjectsAndSid[i]),
  1129. NULL,
  1130. NULL,
  1131. pAceSid[i]);
  1132. }
  1133. // add the entries to the ACL
  1134. //
  1135. *pdwErr = SetEntriesInAcl( ACE_COUNT, rgAccessEntry, NULL, &pDacl );
  1136. if( *pdwErr != 0 )
  1137. {
  1138. DebugLog(( DEB_ERROR, "SetEntriesInAcl() failed\n" ));
  1139. rc = FALSE;
  1140. goto done;
  1141. }
  1142. // build a security descriptor and initialize it
  1143. // in absolute format
  1144. if( !InitializeSecurityDescriptor( pSecurityDescriptor , SECURITY_DESCRIPTOR_REVISION ) )
  1145. {
  1146. DebugLog(( DEB_ERROR, "InitializeSecurityDescriptor() failed\n" ) );
  1147. *pdwErr = GetLastError( );
  1148. rc=FALSE;
  1149. goto done;
  1150. }
  1151. // add DACL to security descriptor (must be in absolute format)
  1152. if( !SetSecurityDescriptorDacl( pSecurityDescriptor,
  1153. TRUE, // bDaclPresent
  1154. pDacl,
  1155. FALSE // bDaclDefaulted
  1156. ) )
  1157. {
  1158. DebugLog(( DEB_ERROR, "SetSecurityDescriptorDacl() failed\n" ));
  1159. *pdwErr = GetLastError( );
  1160. rc=FALSE;
  1161. goto done;
  1162. }
  1163. // set the owner of the directory
  1164. if( !SetSecurityDescriptorOwner( pSecurityDescriptor ,
  1165. pUserSID ,
  1166. FALSE // bOwnerDefaulted
  1167. ) )
  1168. {
  1169. DebugLog(( DEB_ERROR, "SetSecurityDescriptorOwner() failed\n" ));
  1170. *pdwErr = GetLastError( );
  1171. rc= FALSE;
  1172. goto done;
  1173. }
  1174. if ( ! IsValidSecurityDescriptor( pSecurityDescriptor ) )
  1175. {
  1176. DebugLog(( DEB_ERROR , "BAD security desc\n") );
  1177. }
  1178. // build a SECURITY_ATTRIBUTES struct as argument for
  1179. // CreateDirectory()
  1180. securityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES);
  1181. securityAttributes.lpSecurityDescriptor = pSecurityDescriptor;
  1182. securityAttributes.bInheritHandle = FALSE;
  1183. if( !CreateDirectory( szPath , &securityAttributes ) )
  1184. {
  1185. *pdwErr = GetLastError( );
  1186. rc = FALSE;
  1187. goto done;
  1188. }
  1189. else
  1190. {
  1191. rc = TRUE;
  1192. }
  1193. }
  1194. else
  1195. {
  1196. // For local paths we don't need to set security
  1197. // This is the same behavior as exposed thru tsuserex.dll, w2k
  1198. if( !CreateDirectory( szPath , 0) )
  1199. {
  1200. *pdwErr = GetLastError( );
  1201. rc = FALSE;
  1202. goto done;
  1203. }
  1204. else
  1205. {
  1206. rc = TRUE;
  1207. }
  1208. }
  1209. done:
  1210. if( psidAdmins != NULL )
  1211. {
  1212. FreeSid( psidAdmins );
  1213. }
  1214. return rc;
  1215. }
  1216. /****************************************************************************\
  1217. *
  1218. * FUNCTION: TermServ_CreateHomePathAndACLit
  1219. *
  1220. * PURPOSE: create the TS specific user home folder and ACL it such that only
  1221. * user and Admins have access to it.
  1222. *
  1223. * PARAMS: PGLOABLS, from which TSData and userSid are used
  1224. *
  1225. * RETURNS: TRUE if all went ok
  1226. * FALSE if a bad home dir path was specified.
  1227. *
  1228. * HISTORY:
  1229. *
  1230. *
  1231. \****************************************************************************/
  1232. BOOLEAN TermServ_CreateHomePathAndACLit( PGLOBALS pG )
  1233. {
  1234. BOOLEAN rc;
  1235. DWORD dwErr = NO_ERROR;
  1236. BOOLEAN pathIsLocal;
  1237. DWORD dwFileAttribs;
  1238. WLX_TERMINAL_SERVICES_DATA *pTSData;
  1239. pTSData = & pG->MuGlobals.TSData;
  1240. DebugLog((DEB_ERROR, "pTSData->HomeDir = %ws \n", pTSData->HomeDir ));
  1241. if (pTSData->HomeDir[0] == L'\0')
  1242. {
  1243. // no TS specific path, we are done.
  1244. return TRUE;
  1245. }
  1246. // check for empty strings, which means no TS specific path.
  1247. // decide if this is a UNC path to home dir or a local path
  1248. if( pTSData->HomeDir[1] == TEXT( ':' ) && pTSData->HomeDir[2] == TEXT( '\\' ) )
  1249. {
  1250. pathIsLocal = TRUE; // we have a string starting with something like "D:\"
  1251. }
  1252. else if ( pTSData->HomeDir[0] == TEXT( '\\' ) && pTSData->HomeDir[1] == TEXT( '\\' ) )
  1253. {
  1254. pathIsLocal = FALSE; // we have a string like "\\", which means a UNC path
  1255. }
  1256. else
  1257. {
  1258. // we seem to have a bad path, set it to empty so that
  1259. // the default paths will be used by userenv's code for settin up
  1260. // stuff
  1261. pTSData->HomeDirDrive[0] = pTSData->HomeDir[0] = TEXT('\0');
  1262. DebugLog((DEB_ERROR, "Bad path for Terminal Services home folder" ));
  1263. return FALSE;
  1264. }
  1265. dwFileAttribs = GetFileAttributes( pTSData->HomeDir );
  1266. if (dwFileAttribs == - 1)
  1267. {
  1268. dwErr = GetLastError();
  1269. if (dwErr == ERROR_FILE_NOT_FOUND)
  1270. {
  1271. // We need to create the home DIR here, userenv does not create home folders.
  1272. rc = CreateFolderAndACLit_Worker( pTSData->HomeDir , pG->UserProcessData.UserSid , &dwErr , pathIsLocal );
  1273. }
  1274. else
  1275. {
  1276. rc = FALSE;
  1277. }
  1278. }
  1279. else if ( dwFileAttribs & FILE_ATTRIBUTE_DIRECTORY )
  1280. {
  1281. DebugLog((DEB_WARN , ("Homedir folder already exists\n")));
  1282. rc = TRUE;
  1283. }
  1284. else
  1285. {
  1286. // there is a file there, so we can't create a dir...
  1287. DebugLog((DEB_ERROR , "File with the same name already exists: %s\n", pTSData->HomeDir ));
  1288. rc = FALSE;
  1289. }
  1290. if (!rc)
  1291. {
  1292. DebugLog((DEB_ERROR, "TerminalServerCreatedirWorker() returned error = %d\n",dwErr ));
  1293. // we seem to have a bad path, set it to empty so that
  1294. // the default paths will be used by userenv's code for settin up
  1295. // stuff
  1296. pTSData->HomeDirDrive[0] = pTSData->HomeDir[0] = TEXT('\0');
  1297. }
  1298. return rc;
  1299. }
  1300. int
  1301. WINAPI
  1302. WlxLoggedOutSAS(
  1303. PVOID pWlxContext,
  1304. DWORD dwSasType,
  1305. PLUID pAuthenticationId,
  1306. PSID pLogonSid,
  1307. PDWORD pdwOptions,
  1308. PHANDLE phToken,
  1309. PWLX_MPR_NOTIFY_INFO pMprNotifyInfo,
  1310. PVOID * pProfile
  1311. )
  1312. {
  1313. PGLOBALS pGlobals;
  1314. INT_PTR result = 0;
  1315. PWLX_PROFILE_V2_0 pWlxProfile;
  1316. PUNICODE_STRING FlatUser ;
  1317. PUNICODE_STRING FlatDomain ;
  1318. NTSTATUS Status ;
  1319. DWORD dwNewSasType;
  1320. pGlobals = (PGLOBALS) pWlxContext;
  1321. pGlobals->LogonSid = pLogonSid;
  1322. if (ForceAutoLogon())
  1323. {
  1324. pGlobals->IgnoreAutoAdminLogon = FALSE;
  1325. }
  1326. else
  1327. {
  1328. pGlobals->IgnoreAutoAdminLogon = (*pdwOptions) & WLX_OPTION_IGNORE_AUTO_LOGON;
  1329. }
  1330. // Clear out user process information
  1331. ZeroMemory(&pGlobals->UserProcessData, sizeof(pGlobals->UserProcessData));
  1332. if (dwSasType == WLX_SAS_TYPE_AUTHENTICATED) {
  1333. pGlobals->IgnoreAutoAdminLogon = TRUE;
  1334. result = TSAuthenticatedLogon(pGlobals);
  1335. } else {
  1336. do {
  1337. if (result == MSGINA_DLG_SMARTCARD_INSERTED) {
  1338. dwNewSasType = WLX_SAS_TYPE_SC_INSERT;
  1339. } else {
  1340. dwNewSasType = dwSasType;
  1341. }
  1342. result = Logon(pGlobals, dwNewSasType );
  1343. } while (result == MSGINA_DLG_SMARTCARD_INSERTED || result == MSGINA_DLG_SMARTCARD_REMOVED);
  1344. }
  1345. if (result == MSGINA_DLG_SUCCESS)
  1346. {
  1347. DebugLog((DEB_TRACE, "Successful Logon of %ws\\%ws\n", pGlobals->Domain, pGlobals->UserName));
  1348. *phToken = pGlobals->UserProcessData.UserToken;
  1349. *pAuthenticationId = pGlobals->LogonId;
  1350. *pdwOptions = 0;
  1351. //
  1352. // Set up the flat/UPN stuff:
  1353. //
  1354. pGlobals->FlatUserName = pGlobals->UserNameString ;
  1355. pGlobals->FlatDomain = pGlobals->DomainString ;
  1356. //
  1357. // Since win2k domains and later support multiple language sets, and map
  1358. // similar names to the same account for accessibility from non-nls
  1359. // systems (e.g., a user account named "User" can be used to log on
  1360. // as both "User" and "U-with-an-umlaut-ser", we need to always do
  1361. // this lookup to get the "real" name
  1362. //
  1363. if ( ImpersonateLoggedOnUser( pGlobals->UserProcessData.UserToken ) )
  1364. {
  1365. Status = LsaGetUserName( &FlatUser, &FlatDomain );
  1366. if ( NT_SUCCESS( Status ) )
  1367. {
  1368. DuplicateUnicodeString( &pGlobals->FlatUserName, FlatUser );
  1369. DuplicateUnicodeString( &pGlobals->FlatDomain, FlatDomain );
  1370. if ( pGlobals->UserName[0] == L'\0' )
  1371. {
  1372. //
  1373. // Weird case of UPN/SC, no UPN could be found. Use
  1374. // the flat name
  1375. //
  1376. wcscpy( pGlobals->UserName, FlatUser->Buffer );
  1377. RtlInitUnicodeString( &pGlobals->UserNameString,
  1378. pGlobals->UserName );
  1379. }
  1380. LsaFreeMemory( FlatUser->Buffer );
  1381. LsaFreeMemory( FlatUser );
  1382. LsaFreeMemory( FlatDomain->Buffer );
  1383. LsaFreeMemory( FlatDomain );
  1384. }
  1385. RevertToSelf();
  1386. }
  1387. // TS Specific - Send the credentials used for logging on to TermSrv
  1388. // These credentials are used by TermSrv to send back notification to the client
  1389. // Do this only for remote sessions as this is not relevant for sessions logged on from active console
  1390. if (!IsActiveConsoleSession()) {
  1391. _WinStationUpdateClientCachedCredentials( pGlobals->Domain, pGlobals->UserName);
  1392. }
  1393. pMprNotifyInfo->pszUserName = DupString( pGlobals->FlatUserName.Buffer );
  1394. pMprNotifyInfo->pszDomain = DupString(pGlobals->FlatDomain.Buffer );
  1395. RevealPassword( &pGlobals->PasswordString );
  1396. pMprNotifyInfo->pszPassword = DupString(pGlobals->Password);
  1397. HidePassword( &pGlobals->Seed, &pGlobals->PasswordString);
  1398. if (pGlobals->OldPasswordPresent)
  1399. {
  1400. RevealPassword( &pGlobals->OldPasswordString );
  1401. pMprNotifyInfo->pszOldPassword = DupString(pGlobals->OldPassword);
  1402. HidePassword( &pGlobals->OldSeed, &pGlobals->OldPasswordString);
  1403. }
  1404. else
  1405. {
  1406. pMprNotifyInfo->pszOldPassword = NULL;
  1407. }
  1408. DisplayPostShellLogonMessages(pGlobals);
  1409. if ( !g_Console )
  1410. {
  1411. if ( ImpersonateLoggedOnUser( pGlobals->UserProcessData.UserToken ) )
  1412. {
  1413. TermServ_CreateHomePathAndACLit( pGlobals );
  1414. RevertToSelf();
  1415. }
  1416. }
  1417. pWlxProfile = (PWLX_PROFILE_V2_0) LocalAlloc(LMEM_FIXED,
  1418. sizeof(WLX_PROFILE_V2_0));
  1419. if (pWlxProfile)
  1420. {
  1421. DWORD dwSize;
  1422. TCHAR szComputerName[MAX_COMPUTERNAME_LENGTH+1];
  1423. BOOL bDomainLogon = TRUE;
  1424. //
  1425. // See if we logged on locally vs domain (vs cached)
  1426. // Optimized logon uses cached logon, but it should be treated
  1427. // as an ordinary domain logon.
  1428. //
  1429. if ((pGlobals->Profile->UserFlags & LOGON_CACHED_ACCOUNT) &&
  1430. (pGlobals->OptimizedLogonStatus != OLS_LogonIsCached)) {
  1431. bDomainLogon = FALSE;
  1432. } else {
  1433. dwSize = MAX_COMPUTERNAME_LENGTH+1;
  1434. if (GetComputerName (szComputerName, &dwSize)) {
  1435. if (!lstrcmpi (pGlobals->Domain, szComputerName)) {
  1436. DebugLog((DEB_TRACE, "WlxLoggedOutSAS: User logged on locally.\n"));
  1437. bDomainLogon = FALSE;
  1438. }
  1439. }
  1440. }
  1441. pWlxProfile->dwType = WLX_PROFILE_TYPE_V2_0;
  1442. pWlxProfile->pszProfile = AllocAndExpandProfilePath(pGlobals, pMprNotifyInfo->pszUserName);
  1443. pWlxProfile->pszPolicy = (bDomainLogon ? AllocPolicyPath(pGlobals) : NULL);
  1444. pWlxProfile->pszNetworkDefaultUserProfile =
  1445. (bDomainLogon ? AllocNetDefUserProfilePath(pGlobals) : NULL);
  1446. pWlxProfile->pszServerName = (bDomainLogon ? AllocServerName(pGlobals) : NULL);
  1447. pWlxProfile->pszEnvironment = AllocVolatileEnvironment(pGlobals);
  1448. }
  1449. *pProfile = (PVOID) pWlxProfile;
  1450. return(WLX_SAS_ACTION_LOGON);
  1451. }
  1452. else if (DLG_SHUTDOWN(result))
  1453. {
  1454. if (result & MSGINA_DLG_REBOOT_FLAG)
  1455. {
  1456. return(WLX_SAS_ACTION_SHUTDOWN_REBOOT);
  1457. }
  1458. else if (result & MSGINA_DLG_POWEROFF_FLAG)
  1459. {
  1460. return(WLX_SAS_ACTION_SHUTDOWN_POWER_OFF);
  1461. }
  1462. else if (result & MSGINA_DLG_SLEEP_FLAG)
  1463. {
  1464. return(WLX_SAS_ACTION_SHUTDOWN_SLEEP);
  1465. }
  1466. else if (result & MSGINA_DLG_SLEEP2_FLAG)
  1467. {
  1468. return(WLX_SAS_ACTION_SHUTDOWN_SLEEP2);
  1469. }
  1470. else if (result & MSGINA_DLG_HIBERNATE_FLAG)
  1471. {
  1472. return(WLX_SAS_ACTION_SHUTDOWN_HIBERNATE);
  1473. }
  1474. else
  1475. return(WLX_SAS_ACTION_SHUTDOWN);
  1476. }
  1477. else if ( result == MSGINA_DLG_USER_LOGOFF ) {
  1478. return( WLX_SAS_ACTION_LOGOFF );
  1479. }
  1480. else if (result == MSGINA_DLG_SWITCH_CONSOLE)
  1481. {
  1482. return (WLX_SAS_ACTION_SWITCH_CONSOLE);
  1483. }
  1484. else
  1485. {
  1486. if ( pGlobals->RasUsed )
  1487. {
  1488. //
  1489. // Shut down RAS connections on auth failure.
  1490. //
  1491. HangupRasConnections( pGlobals );
  1492. }
  1493. return(WLX_SAS_ACTION_NONE);
  1494. }
  1495. }
  1496. int
  1497. WINAPI
  1498. WlxLoggedOnSAS(
  1499. PVOID pWlxContext,
  1500. DWORD dwSasType,
  1501. PVOID pReserved
  1502. )
  1503. {
  1504. PGLOBALS pGlobals;
  1505. INT_PTR Result;
  1506. DWORD dwType ;
  1507. DWORD cbData ;
  1508. DWORD dwValue ;
  1509. BOOL OkToLock = TRUE ;
  1510. HKEY hkeyPolicy ;
  1511. pGlobals = (PGLOBALS) pWlxContext;
  1512. if ( pGlobals->SmartCardOption &&
  1513. dwSasType == WLX_SAS_TYPE_SC_REMOVE &&
  1514. pGlobals->SmartCardLogon )
  1515. {
  1516. dwValue = 0;
  1517. cbData = sizeof(dwValue);
  1518. RegQueryValueEx(
  1519. WinlogonKey, DISABLE_LOCK_WKSTA,
  1520. 0, &dwType, (LPBYTE)&dwValue, &cbData);
  1521. if (dwValue)
  1522. {
  1523. OkToLock = FALSE ;
  1524. }
  1525. if (OpenHKeyCurrentUser(pGlobals)) {
  1526. if (RegOpenKeyEx(pGlobals->UserProcessData.hCurrentUser,
  1527. WINLOGON_POLICY_KEY,
  1528. 0, KEY_READ, &hkeyPolicy) == ERROR_SUCCESS)
  1529. {
  1530. dwValue = 0;
  1531. cbData = sizeof(dwValue);
  1532. RegQueryValueEx(hkeyPolicy, DISABLE_LOCK_WKSTA,
  1533. 0, &dwType, (LPBYTE)&dwValue, &cbData);
  1534. if (dwValue)
  1535. {
  1536. OkToLock = FALSE ;
  1537. }
  1538. RegCloseKey( hkeyPolicy );
  1539. }
  1540. CloseHKeyCurrentUser(pGlobals);
  1541. }
  1542. if ( OkToLock)
  1543. {
  1544. if ( pGlobals->SmartCardOption == 1 )
  1545. {
  1546. return WLX_SAS_ACTION_LOCK_WKSTA ;
  1547. }
  1548. else if ( pGlobals->SmartCardOption == 2 )
  1549. {
  1550. return WLX_SAS_ACTION_FORCE_LOGOFF ;
  1551. }
  1552. }
  1553. else
  1554. {
  1555. return WLX_SAS_ACTION_NONE ;
  1556. }
  1557. }
  1558. if ( dwSasType != WLX_SAS_TYPE_CTRL_ALT_DEL ) {
  1559. return( WLX_SAS_ACTION_NONE );
  1560. }
  1561. Result = SecurityOptions(pGlobals);
  1562. DebugLog((DEB_TRACE, "Result from SecurityOptions is %d (%#x)\n", Result, Result));
  1563. switch (Result & ~MSGINA_DLG_FLAG_MASK)
  1564. {
  1565. case MSGINA_DLG_SUCCESS:
  1566. case MSGINA_DLG_FAILURE:
  1567. default:
  1568. return(WLX_SAS_ACTION_NONE);
  1569. case MSGINA_DLG_LOCK_WORKSTATION:
  1570. return(WLX_SAS_ACTION_LOCK_WKSTA);
  1571. case MSGINA_DLG_TASKLIST:
  1572. return(WLX_SAS_ACTION_TASKLIST);
  1573. case MSGINA_DLG_USER_LOGOFF:
  1574. return(WLX_SAS_ACTION_LOGOFF);
  1575. case MSGINA_DLG_FORCE_LOGOFF:
  1576. return(WLX_SAS_ACTION_FORCE_LOGOFF);
  1577. case MSGINA_DLG_SHUTDOWN:
  1578. if (Result & MSGINA_DLG_REBOOT_FLAG)
  1579. {
  1580. return(WLX_SAS_ACTION_SHUTDOWN_REBOOT);
  1581. }
  1582. else if (Result & MSGINA_DLG_POWEROFF_FLAG)
  1583. {
  1584. return(WLX_SAS_ACTION_SHUTDOWN_POWER_OFF);
  1585. }
  1586. else if (Result & MSGINA_DLG_SLEEP_FLAG)
  1587. {
  1588. return(WLX_SAS_ACTION_SHUTDOWN_SLEEP);
  1589. }
  1590. else if (Result & MSGINA_DLG_SLEEP2_FLAG)
  1591. {
  1592. return(WLX_SAS_ACTION_SHUTDOWN_SLEEP2);
  1593. }
  1594. else if (Result & MSGINA_DLG_HIBERNATE_FLAG)
  1595. {
  1596. return(WLX_SAS_ACTION_SHUTDOWN_HIBERNATE);
  1597. }
  1598. else
  1599. return(WLX_SAS_ACTION_SHUTDOWN);
  1600. }
  1601. }
  1602. BOOL
  1603. WINAPI
  1604. WlxIsLockOk(
  1605. PVOID pWlxContext
  1606. )
  1607. {
  1608. PGLOBALS pGlobals = (PGLOBALS) pWlxContext ;
  1609. // Stop filtering SC events so SC unlock works
  1610. pWlxFuncs->WlxSetOption( pGlobals->hGlobalWlx,
  1611. WLX_OPTION_USE_SMART_CARD,
  1612. 1,
  1613. NULL
  1614. );
  1615. return(TRUE);
  1616. }
  1617. BOOL
  1618. WINAPI
  1619. WlxIsLogoffOk(
  1620. PVOID pWlxContext
  1621. )
  1622. {
  1623. return(TRUE);
  1624. }
  1625. VOID
  1626. WINAPI
  1627. WlxLogoff(
  1628. PVOID pWlxContext
  1629. )
  1630. {
  1631. PGLOBALS pGlobals;
  1632. pGlobals = (PGLOBALS) pWlxContext;
  1633. pGlobals->UserName[0] = L'\0';
  1634. pGlobals->UserProcessData.UserToken = NULL;
  1635. if (pGlobals->UserProcessData.RestrictedToken != NULL)
  1636. {
  1637. NtClose(pGlobals->UserProcessData.RestrictedToken);
  1638. pGlobals->UserProcessData.RestrictedToken = NULL;
  1639. }
  1640. if ( pGlobals->FlatUserName.Buffer != pGlobals->UserNameString.Buffer )
  1641. {
  1642. LocalFree( pGlobals->FlatUserName.Buffer );
  1643. }
  1644. if ( pGlobals->FlatDomain.Buffer != pGlobals->DomainString.Buffer )
  1645. {
  1646. LocalFree( pGlobals->FlatDomain.Buffer );
  1647. }
  1648. if (pGlobals->UserProcessData.UserSid != NULL)
  1649. {
  1650. LocalFree(pGlobals->UserProcessData.UserSid);
  1651. }
  1652. FreeSecurityDescriptor(pGlobals->UserProcessData.NewThreadTokenSD);
  1653. pGlobals->UserProcessData.NewThreadTokenSD = NULL;
  1654. if (pGlobals->UserProcessData.pEnvironment) {
  1655. VirtualFree(pGlobals->UserProcessData.pEnvironment, 0, MEM_RELEASE);
  1656. pGlobals->UserProcessData.pEnvironment = NULL;
  1657. }
  1658. pGlobals->UserProcessData.Flags = 0 ;
  1659. if ( pGlobals->DnsDomain )
  1660. {
  1661. LocalFree( pGlobals->DnsDomain );
  1662. pGlobals->DnsDomain = NULL ;
  1663. }
  1664. if (pGlobals->Profile)
  1665. {
  1666. LsaFreeReturnBuffer(pGlobals->Profile);
  1667. }
  1668. //
  1669. // No need to zero/NULL pGlobals->OldPassword since it's hashed
  1670. //
  1671. pGlobals->OldPasswordPresent = 0;
  1672. // reset transfered credentials flag.
  1673. pGlobals->TransderedCredentials = FALSE;
  1674. //
  1675. // Only handle AutoAdminLogon if on the console
  1676. //
  1677. if (!g_Console)
  1678. {
  1679. return;
  1680. }
  1681. if (GetProfileInt( APPLICATION_NAME, TEXT("AutoAdminLogon"), 0))
  1682. {
  1683. //
  1684. // If this is auto admin logon, generate a fake SAS right now.
  1685. //
  1686. pWlxFuncs->WlxSasNotify(pGlobals->hGlobalWlx, WLX_SAS_TYPE_CTRL_ALT_DEL);
  1687. }
  1688. return;
  1689. }
  1690. VOID
  1691. WINAPI
  1692. WlxShutdown(
  1693. PVOID pWlxContext,
  1694. DWORD ShutdownType
  1695. )
  1696. {
  1697. //
  1698. // Initialize consumer windows changes
  1699. //
  1700. _Shell_Terminate();
  1701. return;
  1702. }
  1703. BOOL
  1704. WINAPI
  1705. WlxScreenSaverNotify(
  1706. PVOID pWlxContext,
  1707. BOOL * fSecure)
  1708. {
  1709. if (*fSecure)
  1710. { // If it is a secure screen saver,
  1711. // this is equivalent to a lock
  1712. *fSecure = WlxIsLockOk(pWlxContext);
  1713. }
  1714. return( TRUE );
  1715. }
  1716. BOOL
  1717. WINAPI
  1718. WlxNetworkProviderLoad(
  1719. PVOID pWlxContext,
  1720. PWLX_MPR_NOTIFY_INFO pMprNotifyInfo
  1721. )
  1722. {
  1723. PGLOBALS pGlobals;
  1724. pGlobals = (PGLOBALS) pWlxContext;
  1725. pMprNotifyInfo->pszUserName = DupString(pGlobals->UserName);
  1726. pMprNotifyInfo->pszDomain = DupString(pGlobals->Domain);
  1727. RevealPassword( &pGlobals->PasswordString );
  1728. pMprNotifyInfo->pszPassword = DupString(pGlobals->Password);
  1729. HidePassword( &pGlobals->Seed, &pGlobals->PasswordString);
  1730. if (pGlobals->OldPasswordPresent)
  1731. {
  1732. RevealPassword( &pGlobals->OldPasswordString );
  1733. pMprNotifyInfo->pszOldPassword = DupString(pGlobals->OldPassword);
  1734. HidePassword( &pGlobals->OldSeed, &pGlobals->OldPasswordString);
  1735. }
  1736. else
  1737. {
  1738. pMprNotifyInfo->pszOldPassword = NULL;
  1739. }
  1740. return TRUE ;
  1741. }
  1742. VOID
  1743. WINAPI
  1744. WlxReconnectNotify(
  1745. PVOID pWlxContext)
  1746. {
  1747. _Shell_Reconnect();
  1748. }
  1749. VOID
  1750. WINAPI
  1751. WlxDisconnectNotify(
  1752. PVOID pWlxContext)
  1753. {
  1754. _Shell_Disconnect();
  1755. }
  1756. //+---------------------------------------------------------------------------
  1757. //
  1758. // Function: GetErrorDescription
  1759. //
  1760. // Synopsis: Returns the message from ntdll corresponding to the status
  1761. // code.
  1762. //
  1763. // Arguments: [ErrorCode] --
  1764. // [Description] --
  1765. // [DescriptionSize] --
  1766. //
  1767. // History: 5-02-97 RichardW Created
  1768. //
  1769. // Notes:
  1770. //
  1771. //----------------------------------------------------------------------------
  1772. BOOL
  1773. GetErrorDescription(
  1774. DWORD ErrorCode,
  1775. LPWSTR Description,
  1776. DWORD DescriptionSize
  1777. )
  1778. {
  1779. HMODULE Module ;
  1780. //
  1781. // First, try to determine what kind of error code it is:
  1782. //
  1783. //
  1784. // Some people disguise win32 error codes in HRESULTs. While
  1785. // this is annoying, it can be handled.
  1786. //
  1787. if ( ( ErrorCode & 0xFFFF0000 ) == 0x80070000 )
  1788. {
  1789. ErrorCode = ErrorCode & 0x0000FFFF ;
  1790. }
  1791. if ( (ErrorCode > 0) && (ErrorCode < 0x00010000) )
  1792. {
  1793. //
  1794. // Looks like a winerror:
  1795. //
  1796. Module = GetModuleHandle( TEXT("kernel32.dll") );
  1797. }
  1798. else if ( (0xC0000000 & ErrorCode ) == 0xC0000000 )
  1799. {
  1800. //
  1801. // Looks like an NT status
  1802. //
  1803. Module = GetModuleHandle( TEXT("ntdll.dll" ) );
  1804. }
  1805. else
  1806. {
  1807. Module = GetModuleHandle( TEXT("kernel32.dll" ) );
  1808. }
  1809. return FormatMessage( FORMAT_MESSAGE_IGNORE_INSERTS |
  1810. FORMAT_MESSAGE_FROM_HMODULE,
  1811. (LPCVOID) Module,
  1812. ErrorCode,
  1813. 0,
  1814. Description,
  1815. DescriptionSize,
  1816. NULL );
  1817. }
  1818. /*=============================================================================
  1819. == Local Procedures Defined
  1820. =============================================================================*/
  1821. /******************************************************************************
  1822. *
  1823. * FreeAutoLogonInfo
  1824. *
  1825. * Free WLX_CLIENT_CREDENTAILS_INFO and data strings returned
  1826. * from winlogon.
  1827. *
  1828. * ENTRY:
  1829. * pGlobals (input)
  1830. * pointer to GLOBALS struct
  1831. *
  1832. * EXIT:
  1833. * nothing
  1834. *
  1835. *****************************************************************************/
  1836. VOID
  1837. FreeAutoLogonInfo( PGLOBALS pGlobals )
  1838. {
  1839. PWLX_CLIENT_CREDENTIALS_INFO_V2_0 pAutoLogon;
  1840. pAutoLogon = pGlobals->MuGlobals.pAutoLogon;
  1841. if( pAutoLogon == NULL ) {
  1842. return;
  1843. }
  1844. if ( pAutoLogon->pszUserName ) {
  1845. LocalFree( pAutoLogon->pszUserName );
  1846. }
  1847. if ( pAutoLogon->pszDomain ) {
  1848. LocalFree( pAutoLogon->pszDomain );
  1849. }
  1850. if ( pAutoLogon->pszPassword ) {
  1851. LocalFree( pAutoLogon->pszPassword );
  1852. }
  1853. LocalFree( pAutoLogon );
  1854. pGlobals->MuGlobals.pAutoLogon = NULL;
  1855. }