winlogon源码分析

转载自:https://blog.csdn.net/chenyujing1234/article/details/7973618

一、从WinMain开始分析

(1)  获得系统debug信息

NtQuerySystemInformation用于返回指定的系统信息。

 
  1. NTSTATUS WINAPI NtQuerySystemInformation(

  2. _In_ SYSTEM_INFORMATION_CLASS SystemInformationClass,

  3. _Inout_ PVOID SystemInformation,

  4. _In_ ULONG SystemInformationLength,

  5. _Out_opt_ PULONG ReturnLength

  6. );

  7.  

如果是内核debugger使能或 NtCurrentPeb()->BeingDebugged为TRUE,那么设置设置异常处理函数并设置定时器。

 
  1. SetUnhandledExceptionFilter( WinlogonUnhandledExceptionFilter );

  2.  
  3. KernelDebuggerPresent = TRUE ;

  4.  
  5. SetTimerQueueTimer( NULL,

  6. WlpPeriodicBreak,

  7. NULL,

  8. 60 * 1000,

  9. 60 * 1000,

  10. FALSE );

 
  1. ULONG

  2. NTAPI

  3. WlpPeriodicBreak(

  4. PVOID Param,

  5. BOOLEAN Timeout

  6. )

  7. {

  8. LARGE_INTEGER ZeroExpiration;

  9. HANDLE hToken;

  10. DWORD ReturnLength;

  11. TOKEN_STATISTICS TokenStats;

  12. NTSTATUS Status;

  13.  
  14. ZeroExpiration.QuadPart = 0;

  15.  
  16.  
  17. Status = NtOpenProcessToken(

  18. NtCurrentProcess(),

  19. TOKEN_QUERY,

  20. &hToken

  21. );

  22.  
  23. if (NT_SUCCESS( Status )) {

  24.  
  25. Status = NtQueryInformationToken (

  26. hToken,

  27. TokenStatistics,

  28. &TokenStats,

  29. sizeof( TOKEN_STATISTICS ),

  30. &ReturnLength

  31. );

  32.  
  33. if (NT_SUCCESS( Status )) {

  34.  
  35. if (RtlLargeIntegerEqualTo( TokenStats.ExpirationTime, ZeroExpiration )) {

  36.  
  37. DbgBreakPoint();

  38. }

  39. }

  40.  
  41. NtClose( hToken );

  42. }

  43.  
  44.  
  45. if (g_BreakinProcessId != 0) {

  46. Breakin(g_BreakinProcessId);

  47. }

  48.  
  49. return(0);

  50. }


定时器的处理函数中去获得当前TOKEN的TokenStatistics信息,然后取出结果中的TokenStats.ExpirationTime与ZeroExpiration相比。

 
  1. if (RtlLargeIntegerEqualTo( TokenStats.ExpirationTime, ZeroExpiration ))

  2.  


 

(1、1)RtlLargeIntegerEqualTo函数说明:

RtlLargeIntegerEqualTo用于大数比较,看两数是否相等。

 
  1. BOOLEAN

  2. RtlLargeIntegerEqualTo(

  3. IN LARGE_INTEGER Operand1,

  4. IN LARGE_INTEGER Operand2

  5. );

  6.  
  7.  


(1、2)DbgBreakPoint

它进入内核模式的调试器

 
  1. VOID

  2. NTAPI

  3. DbgBreakPoint(

  4. VOID

  5. );

  6.  
  7.  

DbgBreakPoint是内核模式,它等价于DebugBreak。




 

(2)初始化debug支持和logging

 InitDebugSupport();
 
  1. void

  2. InitDebugSupport(void)

  3. {

  4. LoadDebugParameters("WinlogonDebug");

  5. LoadDebugParameters("Winlogon");

  6.  
  7. }


(3)提升winlogon进程优先级,让自己更重要

 
  1. /

  2. // Make ourselves more important

  3. //

  4.  
  5. if (!SetProcessPriority())

  6. {

  7. ExitProcess( EXIT_INITIALIZATION_ERROR );

  8. }

 
  1. BOOL SetProcessPriority(

  2. VOID

  3. )

  4. {

  5. //

  6. // Bump us up to the high priority class

  7. //

  8.  
  9. if (!SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS)) {

  10. DebugLog((DEB_ERROR, "Failed to raise it's own process priority, error = %d", GetLastError()));

  11. return(FALSE);

  12. }

  13.  
  14. //

  15. // Set this thread to high priority since we'll be handling all input

  16. //

  17.  
  18. if (!SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST)) {

  19. DebugLog((DEB_ERROR, "Failed to raise main thread priority, error = %d", GetLastError()));

  20. return(FALSE);

  21. }

  22.  
  23. return(TRUE);

  24. }


(3、1)SetPriorityClass API 说明

设置指定进程的优先级类,这个值和进程中的每个线程的优先级一起决定每个线程的基本优先级级别。

 
  1. BOOL WINAPI SetPriorityClass(

  2. __in HANDLE hProcess,

  3. __in DWORD dwPriorityClass

  4. );

  5.  



 

(4) 映射TCPIP信息

UpdateTcpIpParameters只是做注册表操作。

 
  1. //

  2. // Map the TCPIP information

  3. //

  4.  
  5. UpdateTcpIpParameters();


 

(5)初始化全局变量和环境

 
  1. //

  2. // Initialize the globals

  3. //

  4.  
  5. if ( !InitializeGlobals(hInstance) )

  6. {

  7. ExitProcess( EXIT_INITIALIZATION_ERROR );

  8. }

(5、1) 先判断是不是终端的服务器

判断方法:根据共享数据USER_SHARED_DATA中的SuiteMast位和TerminalServer位决定。

如果是终端服务器那么通过NtQueryInformationProcess获是sessionId。

 
  1. g_IsTerminalServer = !!(USER_SHARED_DATA->SuiteMask & (1 << TerminalServer));

  2.  
  3.  
  4. if (g_IsTerminalServer) {

  5.  
  6. //

  7. // Query Winlogon's Session Id

  8. //

  9.  
  10. if (!NT_SUCCESS(NtQueryInformationProcess(

  11. NtCurrentProcess(),

  12. ProcessSessionInformation,

  13. &SessionInfo,

  14. sizeof(SessionInfo),

  15. NULL

  16. ))) {

  17.  
  18. ASSERT(FALSE);

  19.  
  20. ExitProcess( EXIT_INITIALIZATION_ERROR );

  21.  
  22. }

  23.  
  24. g_SessionId = SessionInfo.SessionId;

  25.  
  26. } else {

  27.  
  28. //

  29. // For Non TerminaServer SessionId is always 0

  30. //

  31. g_SessionId = 0;

  32.  
  33. }

如果是终端服务器,那么载入Winsta.dll并存储函数指针

 
  1. if (g_IsTerminalServer) {

  2.  
  3. if (!InitializeMultiUserFunctionsPtrs()) {

  4. ExitProcess( EXIT_INITIALIZATION_ERROR );

  5. }

  6. }


 

(5、2)向windows登记,这样我们能创建windowstation等。

RegisterLogonProcess无法找到它的定义 。

 
  1. //

  2. // Register with windows so we can create windowstation etc.

  3. //

  4.  
  5. if (!RegisterLogonProcess(HandleToUlong(NtCurrentTeb()->ClientId.UniqueProcess), TRUE)) {

  6. DebugLog((DEB_ERROR, "could not register itself as logon process\n"));

  7. return FALSE;

  8. }

NtCurrentTeb()来获取TEB的地址和PEB的地址。
(5、3 )获得sid,这样它能被放在ACLs中。

主要通过三个API函数:

RtlLengthRequiredSid获得要求的SID长;

RtlInitializeSid初始化SID;

RtlSubAuthoritySid             ;

 
  1. //

  2. // Get our sid so it can be put on object ACLs

  3. //

  4.  
  5. SidLength = RtlLengthRequiredSid(1);

  6. g_WinlogonSid = (PSID)Alloc(SidLength);

  7. ASSERTMSG("Winlogon failed to allocate memory for system sid", g_WinlogonSid != NULL);

  8.  
  9. RtlInitializeSid(g_WinlogonSid, &SystemSidAuthority, 1);

  10. *(RtlSubAuthoritySid(g_WinlogonSid, 0)) = SECURITY_LOCAL_SYSTEM_RID;


(5、4)获得安装信息

安装类型是从注册表中读出来的。

 
  1. //

  2. // Get setup information

  3. //

  4.  
  5. g_uSetupType = CheckSetupType() ;

  6. g_fExecuteSetup = (g_uSetupType == SETUPTYPE_FULL) ||

  7. (g_uSetupType == SETUPTYPE_UPGRADE)


(5、5)获得电脑名字并设置环境变量,这样我们能在之后查看到它。

GetComputerName为系统API

 
  1. // Get a copy of the computer name in *my* environment, so that we

  2. // can look at it later.

  3. //

  4.  
  5. if (GetComputerName (szComputerName, &dwComputerNameSize)) {

  6. SetEnvironmentVariable(COMPUTERNAME_VARIABLE, (LPTSTR) szComputerName);

  7. }


(5、6)

 
  1. //

  2. // Set the default USERPROFILE and ALLUSERSPROFILE locations

  3. //

  4.  
  5. if (g_fExecuteSetup) {

  6. DetermineProfilesLocation(((g_uSetupType == SETUPTYPE_FULL) ? TRUE : FALSE));

  7. }

  8.  
  9. dwSize = ARRAYSIZE(szProfile);

  10. if (GetDefaultUserProfileDirectory (szProfile, &dwSize)) {

  11. SetEnvironmentVariable(USERPROFILE_VARIABLE, szProfile);

  12. }

  13.  
  14. dwSize = ARRAYSIZE(szProfile);

  15. if (GetAllUsersProfileDirectory (szProfile, &dwSize)) {

  16. SetEnvironmentVariable(ALLUSERSPROFILE_VARIABLE, szProfile);

  17. }

(6)检查分页文件

 
  1. //

  2. // Check the pagefile

  3. //

  4.  
  5. if (!g_fExecuteSetup)

  6. {

  7. CreateTemporaryPageFile();

  8. }



(6、1)删除系统目录中的temppf.sys文件。

(6、2)检查看是否我们有一个分页文件,如果没有提醒用户

先用NtQuerySystemInformation查询页文件信息和系统表现系统,以它们的结果来判断是否有页文件。

 
  1. PfiStatus = NtQuerySystemInformation(

  2. SystemPageFileInformation,

  3. &pfi,

  4. sizeof(pfi),

  5. &ReturnLength

  6. );

  7.  
  8. PiStatus = NtQuerySystemInformation(

  9. SystemPerformanceInformation,

  10. &PerfInfo,

  11. sizeof(PerfInfo),

  12. NULL

  13. );

(6、3)如果没有页文件,或总共提交的限制是最小的,那么我们创建一个增加折分页文件并告诉用户去做一些事情。
(6、3、1)创建临时的系统分页,

(6、3、2)创建一个20mb的分页文件。

创建成功后, 就把文件移动到新创建的分页文件中。

 
  1. st = NtCreatePagingFile(

  2. (PUNICODE_STRING)&FileName,

  3. &MinPagingFileSize,

  4. &MaxPagingFileSize,

  5. 0

  6. );

  7.  
  8. if (!NT_SUCCESS( st )) {

  9.  
  10. if ( FileSizeInMegabytes > 0 ) {

  11. FileSizeInMegabytes -= 2;

  12. MinPagingFileSize = RtlEnlargedIntegerMultiply(FileSizeInMegabytes,0x100000);

  13. MaxPagingFileSize = MinPagingFileSize;

  14. goto retry;

  15. }

  16. } else {

  17. MoveFileExW(PagingFileName.Buffer,NULL,MOVEFILE_DELAY_UNTIL_REBOOT);

  18.  
  19. }


 

 (7)初始化安全模块

 
  1. //

  2. // Initialize security

  3. //

  4.  
  5. if (!InitializeSecurity ())

  6. {

  7. ExitProcess( EXIT_SECURITY_INIT_ERROR );

  8. }


 

 
  1. BOOL

  2. InitializeSecurity(

  3. VOID)

  4. {

  5. //

  6. // Set up our module globals

  7. //

  8. InitializeSecurityGlobals();

  9.  
  10. //

  11. // Initialize the removable medial module

  12. //

  13.  
  14. RmvInitializeRemovableMediaSrvcs();

  15.  
  16. return TRUE;

  17. }

 

(7、1)设置模块全局变量

初始化全局变量的内容(主要是通过RtlAllocateAndInitializeSid,指定不同的类型得到不同的SID:本地SID、admin SID、限制的SID)

 
  1. VOID

  2. InitializeSecurityGlobals(

  3. VOID

  4. )

  5. {

  6. NTSTATUS Status;

  7. SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;

  8.  
  9.  
  10. //

  11. // Initialize the local sid for later

  12. //

  13.  
  14. Status = RtlAllocateAndInitializeSid(

  15. &gLocalSidAuthority,

  16. 1,

  17. SECURITY_LOCAL_RID,

  18. 0, 0, 0, 0, 0, 0, 0,

  19. &gLocalSid

  20. );

  21.  
  22. if (!NT_SUCCESS(Status)) {

  23. DebugLog((DEB_ERROR, "Failed to initialize local sid, status = 0x%lx", Status));

  24. }

  25.  
  26. //

  27. // Initialize the admin sid for later

  28. //

  29.  
  30. Status = RtlAllocateAndInitializeSid(

  31. &gSystemSidAuthority,

  32. 2,

  33. SECURITY_BUILTIN_DOMAIN_RID,

  34. DOMAIN_ALIAS_RID_ADMINS,

  35. 0, 0, 0, 0, 0, 0,

  36. &gAdminSid

  37. );

  38. if (!NT_SUCCESS(Status)) {

  39. DebugLog((DEB_ERROR, "Failed to initialize admin alias sid, status = 0x%lx", Status));

  40. }

  41.  
  42. Status = RtlAllocateAndInitializeSid(

  43. & NtAuthority ,

  44. 1,

  45. SECURITY_RESTRICTED_CODE_RID,

  46. 0, 0, 0, 0, 0, 0, 0,

  47. &gRestrictedSid

  48. );

  49.  
  50. if (!NT_SUCCESS(Status)) {

  51. DebugLog((DEB_ERROR, "Failed to initialize restricted sid, status = 0x%lx", Status));

  52. }

  53.  
  54.  
  55. }

  56.  


 

(7、2)初始化可移除的中间模块

通过RtlAllocateAndInitializeSid,指定不同的类型(SECURITY_LOCAL_SYSTEM_RID、SECURITY_BUILTIN_DOMAIN_RID、SECURITY_BUILTIN_DOMAIN_RID)得到不同的SID。

 

 
  1. BOOL

  2. RmvInitializeRemovableMediaSrvcs(

  3. VOID

  4. )

  5. {

  6. NTSTATUS

  7. Status;

  8.  
  9. SID_IDENTIFIER_AUTHORITY

  10. NtAuthority = SECURITY_NT_AUTHORITY;

  11.  
  12.  
  13. //

  14. // See if we need to protect floppy and/or CDRom drives.

  15. //

  16.  
  17.  
  18. //

  19. // 初始化需要知道的SID

  20. //

  21.  
  22. Status = RtlAllocateAndInitializeSid( &NtAuthority,

  23. 1,

  24. SECURITY_LOCAL_SYSTEM_RID,

  25. 0, 0, 0, 0, 0, 0, 0,

  26. &RmvpLocalSystemSid

  27. );

  28.  
  29. if ( !NT_SUCCESS(Status) )

  30. {

  31. return FALSE ;

  32. }

  33.  
  34. Status = RtlAllocateAndInitializeSid( &NtAuthority,

  35. 2,

  36. SECURITY_BUILTIN_DOMAIN_RID,

  37. DOMAIN_ALIAS_RID_ADMINS,

  38. 0, 0, 0, 0, 0, 0,

  39. &RmvpAdministratorsSid

  40. );

  41.  
  42. if ( !NT_SUCCESS(Status) )

  43. {

  44. return FALSE ;

  45. }

  46.  
  47. Status = RtlAllocateAndInitializeSid( &NtAuthority,

  48. 2,

  49. SECURITY_BUILTIN_DOMAIN_RID,

  50. DOMAIN_ALIAS_RID_POWER_USERS,

  51. 0, 0, 0, 0, 0, 0,

  52. &RmvpPowerUsersSid );

  53.  
  54. if ( !NT_SUCCESS(Status) )

  55. {

  56. return FALSE ;

  57. }

  58.  
  59. RtlInitUnicodeString( &RmvpNtfs, L"\\ntfs" );

  60. RtlInitUnicodeString( &RmvpFat, L"\\fat" );

  61. RtlInitUnicodeString( &RmvpCdfs, L"\\cdfs" );

  62.  
  63. return TRUE ;

  64. }


 

(8)创建主终端

 
  1. //

  2. // Create the primary terminal.

  3. //

  4.  
  5. if (!CreatePrimaryTerminal())

  6. {

  7. DebugLog((DEB_TRACE_INIT, "CreatePrimaryTerminal failed\n"));

  8. ExitProcess( EXIT_PRIMARY_TERMINAL_ERROR );

  9. }

(8、1)为terminal分配空间,并初始化成员变量

 
  1. //

  2. // Check mark

  3. //

  4. pTerm->CheckMark = TERMINAL_CHECKMARK;

  5.  
  6. ZeroMemory(pTerm->Mappers, sizeof(WindowMapper) * MAX_WINDOW_MAPPERS);

  7. pTerm->cActiveWindow = 0;

  8. pTerm->PendingSasHead = 0;

  9. pTerm->PendingSasTail = 0;

 

(8、2)  如果不是控制台模式,那么等待连接,并确保指向它的sessionId

gpfnWinStationWaitForConnect接口从winsta.dll获得

 

 
  1. //

  2. // Wait here for the connection

  3. //

  4. if ( !g_Console ) {

  5. if ( !gpfnWinStationWaitForConnect() ) {

  6. DebugLog((DEB_ERROR, "wait for connect failed\n"));

  7. return(FALSE);

  8. }

  9. }


 

 
  1. if (!g_Console) {

  2. if (!NT_SUCCESS(SetWinlogonDeviceMap(g_SessionId))) {

  3. ExitProcess( EXIT_DEVICE_MAP_ERROR );

  4. }

  5. }

 
  1. /***************************************************************************\

  2. * SetWinlogonDeviceMap

  3. *

  4. * For non-console winlogon's, make them point to the session specific

  5. * DeviceMap.

  6. *

  7. * History:

  8. * 09-November-1997 SalimC Created

  9. \***************************************************************************/

  10. NTSTATUS

  11. SetWinlogonDeviceMap( ULONG SessionId)

  12. {

  13. NTSTATUS Status = STATUS_SUCCESS;

  14. WCHAR szSessionString[MAX_SESSION_PATH];

  15. UNICODE_STRING UnicodeString;

  16. OBJECT_ATTRIBUTES Obja;

  17. PROCESS_DEVICEMAP_INFORMATION ProcessDeviceMapInfo;

  18. HANDLE DosDevicesDirectory;

  19.  
  20.  
  21.  
  22. if (SessionId == 0) {

  23.  
  24. return STATUS_INVALID_PARAMETER;

  25.  
  26. }

  27.  
  28. swprintf(szSessionString,L"\\Sessions\\%ld\\DosDevices",SessionId);

  29.  
  30. RtlInitUnicodeString( &UnicodeString, szSessionString );

  31.  
  32.  
  33. InitializeObjectAttributes( &Obja,

  34. &UnicodeString,

  35. OBJ_CASE_INSENSITIVE,

  36. NULL,

  37. NULL

  38. );

  39.  
  40. Status = NtOpenDirectoryObject( &DosDevicesDirectory,

  41. DIRECTORY_ALL_ACCESS,

  42. &Obja

  43. );

  44. if (!NT_SUCCESS( Status )) {

  45.  
  46. return Status;

  47.  
  48. }

  49.  
  50.  
  51.  
  52. //

  53. // 设置Winlogon的 ProcessDeviceMap 到会话指定的DosDevices 目录

  54. //

  55.  
  56. ProcessDeviceMapInfo.Set.DirectoryHandle = DosDevicesDirectory;

  57.  
  58. Status = NtSetInformationProcess( NtCurrentProcess(),

  59. ProcessDeviceMap,

  60. &ProcessDeviceMapInfo.Set,

  61. sizeof( ProcessDeviceMapInfo.Set )

  62. );

  63.  
  64. NtClose(DosDevicesDirectory);

  65.  
  66.  
  67. return Status;

  68.  
  69. }


(8、3) 创建交互的window station
(8、3、1) 为WindowStation分配空间,并设置窗口名字为WinSta0

 
  1. //

  2. // Allocate space for a new WindowStation

  3. //

  4. pWS = LocalAlloc (LPTR, sizeof(WINDOWSTATION) +

  5. (lstrlenW(WINDOW_STATION_NAME) + 1) * sizeof(WCHAR));

  6. if (!pWS) {

  7. DebugLog((DEB_ERROR, "Could not allocate windowstation structure\n"));

  8. goto failCreateTerminal;

  9. }

  10.  
  11. //

  12. // Save the name

  13. //

  14. pWS->lpWinstaName = (LPWSTR)((LPBYTE) pWS + sizeof(WINDOWSTATION));

  15. lstrcpyW (pWS->lpWinstaName, WINDOW_STATION_NAME);


(8、3、2)  用API  CreateWindowStationW  创建窗口station ,并设置它为进程的window station

 
  1. // Create the window station

  2. //

  3. pWS->hwinsta = CreateWindowStationW (WINDOW_STATION_NAME, 0, MAXIMUM_ALLOWED, NULL);

  4. if (!pWS->hwinsta) {

  5. DebugLog((DEB_ERROR, "Could not create the interactive windowstation\n"));

  6. goto failCreateTerminal;

  7. }

  8.  
  9. SetProcessWindowStation(pWS->hwinsta);


(8、3、3) 初始化winsta的安全性

InitializeWinstaSecurity完成初始化window station 安全性。

 InitializeWinstaSecurity(pWS);


(8、3、3、1)创建Ace列表,目的是跟踪对winsta的访问

 
  1. pList = CreateAceList( 16 );

  2.  
  3. if ( !pList )

  4. {

  5. return( FALSE );

  6. }

  7.  
  8. pWS->Acl = pList;

(8、3、3、2) SetMyAce设置来定义winlogon的ACEs

eg:

 
  1. SetMyAce(& ( pList->Aces[ pList->Active ++ ]),

  2. g_WinlogonSid,

  3. WINSTA_ALL,

  4. NO_PROPAGATE_INHERIT_ACE

  5. );

(8、3、3、3)AceListSetWinstaSecurity根据(8、3、3、2)定义的ACEs来设置winsta的安全性

这一特殊的安全描述符了:除非得到Winlogon的明确许可,否则没有其他的进程可以访问此窗口站。参考文章<<>>

 
  1. BOOL

  2. AceListSetWinstaSecurity(

  3. PMYACELIST pList,

  4. DWORD Count,

  5. HWINSTA hWinsta )

  6. {

  7. PSECURITY_DESCRIPTOR SecurityDescriptor;

  8. SECURITY_INFORMATION si;

  9. BOOL Result;

  10.  
  11. //

  12. // Create the security descriptor

  13. //

  14.  
  15. SecurityDescriptor = CreateSecurityDescriptor(pList->Aces, Count );

  16. if (SecurityDescriptor == NULL) {

  17. DebugLog((DEB_ERROR, "failed to create winsta security descriptor\n"));

  18. return(FALSE);

  19. }

  20.  
  21. //

  22. // Set the DACL on the object

  23. //

  24.  
  25. si = DACL_SECURITY_INFORMATION;

  26. Result = SetUserObjectSecurity(hWinsta, &si, SecurityDescriptor);

  27.  
  28. //

  29. // Free up the security descriptor

  30. //

  31.  
  32. DeleteSecurityDescriptor(SecurityDescriptor);

  33.  
  34. //

  35. // Return success status

  36. //

  37.  
  38. if (!Result) {

  39. DebugLog((DEB_ERROR, "failed to set windowstation security\n"));

  40. }

  41. return(Result);

  42. }



(8、3、4) 创建winlogon的桌面及应用程序桌面

 
  1. //

  2. // Create winlogon's desktop

  3. //

  4. pWS->hdeskWinlogon = CreateDesktopW (WINLOGON_DESKTOP_NAME,

  5. NULL, NULL, 0, MAXIMUM_ALLOWED, NULL);

  6. if (!pWS->hdeskWinlogon) {

  7. DebugLog((DEB_ERROR, "Could not create winlogon's desktop\n"));

  8. goto failCreateTerminal;

  9. }

  10.  
  11. //

  12. // Create the application desktop

  13. //

  14. pWS->hdeskApplication = CreateDesktopW (APPLICATION_DESKTOP_NAME,

  15. NULL, NULL, 0, MAXIMUM_ALLOWED, NULL);

  16. if (!pWS->hdeskApplication) {

  17. DebugLog((DEB_ERROR, "Could not create application's desktop\n"));

  18. goto failCreateTerminal;

  19. }


(8、3、5)设置winlogon桌面的安全性及应用程序桌面的安全性

方法与(8、3、3、2)(8、3、3、3)类似。

 
  1. //

  2. // Set desktop security (no user access yet)

  3. //

  4. if (!SetWinlogonDesktopSecurity(pWS->hdeskWinlogon, g_WinlogonSid)) {

  5. DebugLog((DEB_ERROR, "Failed to set winlogon desktop security\n"));

  6. }

  7. if (!SetUserDesktopSecurity(pWS->hdeskApplication, NULL, g_WinlogonSid)) {

  8. DebugLog((DEB_ERROR, "Failed to set application desktop security\n"));

  9. }


(8、3、6)转换到winlogon的桌面

 
  1. //

  2. // Switch to the winlogon desktop

  3. //

  4. SetActiveDesktop(pTerm, Desktop_Winlogon);


 

 
  1. BOOL

  2. SetActiveDesktop(

  3. PTERMINAL pTerm,

  4. ActiveDesktops Desktop)

  5. {

  6. HDESK hDesk;

  7. HDESK hPrevious;

  8. DWORD LengthNeeded;

  9. PWINDOWSTATION pWS = pTerm->pWinStaWinlogon;

  10.  
  11. if (Desktop == pWS->ActiveDesktop)

  12. {

  13. return(TRUE);

  14. }

  15.  
  16. if (pWS->ActiveDesktop == Desktop_Application)

  17. {

  18. LockWindowStation(pWS->hwinsta);

  19. pWS->hdeskPrevious = OpenInputDesktop(0, FALSE, MAXIMUM_ALLOWED);

  20.  
  21. if (!GetUserObjectInformation( pWS->hdeskPrevious,

  22. UOI_NAME,

  23. pTerm->pszDesktop,

  24. pTerm->DesktopLength,

  25. &LengthNeeded) )

  26. {

  27. if (pTerm->DesktopLength != TYPICAL_STRING_LENGTH &&

  28. pTerm->DesktopLength != 0)

  29. {

  30. LocalFree( pTerm->pszDesktop );

  31. pTerm->pszDesktop = NULL;

  32. pTerm->DesktopLength = 0;

  33. }

  34. pTerm->pszDesktop = LocalAlloc( LMEM_FIXED, LengthNeeded );

  35. if (pTerm->pszDesktop)

  36. {

  37. pTerm->DesktopLength = LengthNeeded;

  38.  
  39. if (!GetUserObjectInformation( pWS->hdeskPrevious,

  40. UOI_NAME,

  41. pTerm->pszDesktop,

  42. pTerm->DesktopLength,

  43. &LengthNeeded))

  44. {

  45. pTerm->pszDesktop[0] = 0;

  46. }

  47. }

  48. else

  49. {

  50. pTerm->DesktopLength = 0;

  51. }

  52. }

  53.  
  54. DebugLog((DEB_TRACE, "Source desktop was %ws\n", pTerm->pszDesktop));

  55. }

  56.  
  57. switch (Desktop)

  58. {

  59. case Desktop_Winlogon:

  60. hDesk = pWS->hdeskWinlogon;

  61. break;

  62. case Desktop_ScreenSaver:

  63. hDesk = pWS->hdeskScreenSaver;

  64. break;

  65. case Desktop_Application:

  66. if (pWS->hdeskPrevious)

  67. {

  68. hDesk = pWS->hdeskPrevious;

  69. }

  70. else

  71. {

  72. hDesk = pWS->hdeskApplication;

  73. }

  74. break;

  75. default:

  76. DebugLog((DEB_ERROR, "Error: Invalid desktop specified %d\n", Desktop));

  77. return(FALSE);

  78. }

  79. if (SwitchDesktop(hDesk))

  80. {

  81. DebugLog((DEB_TRACE, "Switching desktop from %s to %s\n",

  82. DbgGetDesktopName(pWS->ActiveDesktop),

  83. DbgGetDesktopName(Desktop) ));

  84.  
  85. pWS->PreviousDesktop = pWS->ActiveDesktop;

  86. pWS->ActiveDesktop = Desktop;

  87.  
  88. //

  89. // If we're switching back to the user's desktop, then unlock the

  90. // window station, so that the user can switch desktops again. Also,

  91. // close our handle to the desktop. Note! Unlock before close, so

  92. // that if this is the last handle to the desktop, cleanup can occur

  93. // correctly.

  94. //

  95.  
  96. if (pWS->ActiveDesktop == Desktop_Application)

  97. {

  98. UnlockWindowStation(pWS->hwinsta);

  99. if (pWS->hdeskPrevious)

  100. {

  101. DebugLog((DEB_TRACE, "Closing handle %x to users desktop\n", pWS->hdeskPrevious));

  102. CloseDesktop(pWS->hdeskPrevious);

  103. pWS->hdeskPrevious = NULL;

  104. }

  105. }

  106.  
  107.  
  108. return(TRUE);

  109. }

  110. DebugLog((DEB_WARN, "Could not switch desktop!\n"));

  111. return(FALSE);

  112. }

  113.  

(8、3、7) 保存terminal 

(9)从注册表中检查是不是安全模式

(10)设置线程到winlogon的桌面

SetThreadDesktop为系统API

 
  1. //

  2. // Set this thread to winlogon's desktop

  3. //

  4.  
  5. SetThreadDesktop( pTerm->pWinStaWinlogon->hdeskWinlogon );


(11)改变用户到‘system‘

 

 
  1. // Change user to 'system'

  2. //

  3. if (!SecurityChangeUser(pTerm, NULL, NULL, g_WinlogonSid, FALSE)) {

  4. DebugLog((DEB_ERROR, "failed to set user to system\n"));

  5. }


 上面指定的UserLoggedOn为FALSE,在K、中也调用到SecurityChangeUser函数,它的UserLoggedOn为TRUE。

 
  1. BOOL

  2. SecurityChangeUser(

  3. PTERMINAL pTerm,

  4. HANDLE Token,

  5. PQUOTA_LIMITS Quotas OPTIONAL,

  6. PSID LogonSid,

  7. BOOL UserLoggedOn

  8. )

  9. {

  10. PWINDOWSTATION pWS = pTerm->pWinStaWinlogon;

  11. LUID luidNone = { 0, 0 };

  12.  
  13. //

  14. // Save the token for this windowstation

  15. //

  16.  
  17. pWS->hToken = Token;

  18.  
  19. //

  20. // Set appropriate protection on windows objects

  21. //

  22.  
  23. if (UserLoggedOn || g_fExecuteSetup)

  24. {

  25. AddUserToWinsta( pWS,

  26. LogonSid,

  27. Token );

  28.  
  29. }

  30. else

  31. {

  32. RemoveUserFromWinsta( pWS,

  33. pWS->UserProcessData.UserToken );

  34. }

  35.  
  36. SetUserDesktopSecurity(pWS->hdeskApplication,

  37. LogonSid,

  38. g_WinlogonSid);

  39.  
  40. //

  41. // Setup new-process data

  42. //

  43.  
  44. SetUserProcessData(&pWS->UserProcessData,

  45. Token,

  46. Quotas,

  47. LogonSid,

  48. g_WinlogonSid);

  49.  
  50. //

  51. // Setup the appropriate new environment

  52. //

  53.  
  54. if (UserLoggedOn) {

  55.  
  56. //

  57. // Do nothing to the profile or environment. Environment and profiles

  58. // are all handled in wlx.c:LogonAttempt and DoStartShell

  59. //

  60.  
  61. pTerm->LogoffFlags = 0;

  62. pTerm->TickCount = GetTickCount();

  63.  
  64. } else {

  65.  
  66. //

  67. // Restore the system environment

  68. //

  69.  
  70. CloseIniFileUserMapping(pTerm);

  71.  
  72. //

  73. // ResetEnvironment if we are the console or

  74. // we are not logging off. This prevents screen paints during logout

  75. //

  76. if ( g_Console || !pTerm->MuGlobals.fLogoffInProgress )

  77. ResetEnvironment(pTerm);

  78.  
  79. SetWindowStationUser(pWS->hwinsta, &luidNone, NULL, 0);

  80.  
  81. }

  82.  
  83.  
  84. //

  85. // Store whether there is a real user logged on or not

  86. //

  87.  
  88. pTerm->UserLoggedOn = UserLoggedOn;

  89.  
  90. return(TRUE);

  91. }

(12)如果是控制台, 建造网络提供者事件(当网络列表改变时,此事件被触发)

 
  1. //

  2. // For the console winlogon, set the event that is toggled

  3. // when the network provider list changes

  4. //

  5.  
  6. if (g_Console) {

  7.  
  8. CreateNetworkProviderEvent();

  9.  
  10. }


(13) 初始化通知列表和JobControl

 
  1. if ( !WlpInitializeNotifyList( pTerm ) ||

  2. !InitializeJobControl() ||

  3. !LogoffLockInit() )

  4. {

  5. ExitProcess( EXIT_NO_MEMORY );

  6. }


(14) 启动系统进行

 
  1. //

  2. // Start the system processes

  3. //

  4.  
  5. DebugLog((DEB_TRACE_INIT, "Execute system processes:\n"));

  6.  
  7. if (!ExecSystemProcesses())

  8. {

  9. DebugLog((DEB_TRACE_INIT, "ExecSystemProcesses failed\n"));

  10. ExitProcess( EXIT_SYSTEM_PROCESS_ERROR );

  11. }

(15)在我们登陆之前启动APP桌面线程

 
  1. #ifndef _WIN64

  2.  
  3. StartAppDesktopThread(pTerm);

  4.  
  5. #endif // _WIN64


 

 
  1. VOID StartAppDesktopThread(

  2. PTERMINAL pTerm)

  3. {

  4. HANDLE hAppDesktopThread;

  5. DWORD dwThreadId;

  6.  
  7. if (gbADTRunning) {

  8. NDDETRACE(("NetddeAgentThread: aready running\n"));

  9. return;

  10. }

  11.  
  12. hAppDesktopThread = CreateThread(NULL, 0, ApplicationDesktopThread,

  13. (LPVOID)pTerm, 0, &dwThreadId);

  14.  
  15. CloseHandle(hAppDesktopThread);

  16. }

 

ApplicationDesktopThread线程中做以下事情:

(15、1)设置线程运行在WinSta0\Default

注意:在(10)是设置线程到winlogon的桌面。

SetThreadDesktop(pTerm->pWinStaWinlogon->hdeskApplication);

(15、2)初始化窗口数据并注册窗口类

初始化工作包括:注册窗口消息、获得IMM32.DLL模块的ImmDisableIme  接口 ,然后调用。

 
  1. int NDDEAgntInit(

  2. VOID)


 

 
  1. int NDDEAgntInit(

  2. VOID)

  3. {

  4. WNDCLASS WndClass;

  5.  
  6. wMsgNddeAgntExecRtn = RegisterWindowMessage(szAgentExecRtn);

  7. wMsgNddeAgntWakeUp = RegisterWindowMessage(szAgentWakeUp);

  8. wMsgNddeAgntAlive = RegisterWindowMessage(szAgentAlive);

  9. wMsgNddeAgntDying = RegisterWindowMessage(szAgentDying);

  10.  
  11. {

  12. WCHAR wszImmFile[MAX_PATH];

  13. BOOL (WINAPI* fpImmDisableIme)(DWORD);

  14. HMODULE hImm;

  15.  
  16. GetImmFileName(wszImmFile);

  17. hImm = GetModuleHandleW(wszImmFile);

  18. if (hImm) {

  19. fpImmDisableIme = (BOOL (WINAPI*)(DWORD))GetProcAddress(hImm, "ImmDisableIme");

  20. if (fpImmDisableIme) {

  21. #ifndef LATER

  22. fpImmDisableIme(0);

  23. #else

  24. fpImmDisableIme(-1);

  25. #endif

  26. }

  27. }

  28. }

  29.  
  30. ZeroMemory(&WndClass, sizeof(WndClass));

  31.  
  32. WndClass.lpszClassName = (LPTSTR)SZ_NDDEAGNT_CLASS;

  33. WndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);

  34. WndClass.hInstance = hInst;

  35. WndClass.lpfnWndProc = NDDEAgntWndProc;

  36.  
  37. RegisterClass(&WndClass);

  38. return TRUE;

  39. }


(15、3) 创建窗口

g_hwndAppDesktopThread为   netdde 代理的主窗口。

 
  1. /*

  2. * now create the window

  3. */

  4. g_hwndAppDesktopThread = CreateWindowEx(WS_EX_TOPMOST, gszAppName,

  5. szTitle,

  6. WS_OVERLAPPEDWINDOW,

  7. CW_USEDEFAULT,

  8. CW_USEDEFAULT,

  9. CW_USEDEFAULT,

  10. CW_USEDEFAULT,

  11. NULL,

  12. NULL,

  13. hInst,

  14. NULL);

(15、4)  清除任何未信任的共享。

 
  1. /* set up lpszServer for NDDEAPI calls */

  2. GetComputerName(szComputerName, &cbName);

  3. _tcscpy(lpszServer, TEXT("\\\\"));

  4. _tcscat(lpszServer, szComputerName);

  5.  
  6. /*

  7. * clean up any trusted shares that have been modified or deleted

  8. * since we last ran for this user

  9. */

  10. if (IsServiceActive(&hSvcNetDDE, szNetDDE, FALSE)) {

  11. CleanupTrustedShares();

  12. }


(15、5)  分发窗口消息,进入消息循环

 
  1. while (GetMessage(&msg, 0, 0, 0)) {

  2. TranslateMessage(&msg);

  3. DispatchMessage(&msg);

  4. }


 

 

 

 

 

 

 

 

 

(16) misc初始化,它需要在第一个terminal被创建时被调用。

 
  1. //

  2. // Finish some misc initialization. Note: This call can drop into setup

  3. //

  4.  
  5. MiscInitialization(pTerm);


 

 
  1. VOID MiscInitialization (PTERMINAL pTerm)

  2. {

  3. DWORD Win31MigrationFlags;

  4.  
  5.  
  6. //

  7. // Decide what to do about setup

  8. //

  9.  
  10. if (g_fExecuteSetup)

  11. {

  12. //

  13. // Init winmm

  14. //

  15.  
  16. #if !defined(_WIN64_LOGON)

  17.  
  18. try

  19. {

  20. waveOutGetNumDevs();

  21. }

  22. except ( EXCEPTION_EXECUTE_HANDLER )

  23. {

  24. DebugLog(( DEB_ERROR, "Failed to initialize winmm, %x\n", GetExceptionCode() ));

  25. }

  26.  
  27. #endif

  28.  
  29. //

  30. // Run setup and reboot

  31. //

  32.  
  33. ExecuteSetup(pTerm);

  34. EnablePrivilege(SE_SHUTDOWN_PRIVILEGE, TRUE);

  35. NtShutdownSystem(ShutdownReboot);

  36.  
  37. }

  38. else

  39. {

  40. //

  41. // In the case of running setup in mini-setup mode,

  42. // we want to be able to continue through and let the

  43. // user logon.

  44. //

  45. if(g_uSetupType == SETUPTYPE_NOREBOOT) {

  46.  
  47. //

  48. // go execute setup

  49. //

  50. ExecuteSetup(pTerm);

  51. }

  52.  
  53. //

  54. // Don't go any further if setup didn't complete fully. If this

  55. // machine has not completed setup correctly, this will not return.

  56. //

  57.  
  58. CheckForIncompleteSetup(g_pTerminals);

  59. }

  60.  
  61.  
  62. if (!IsWin9xUpgrade()) {

  63. //

  64. // Check to see if there is any WIN.INI or REG.DAT to migrate into

  65. // Windows/NT registry.

  66. //

  67. // This code is skipped when the previous OS was Win9x.

  68. //

  69.  
  70. Win31MigrationFlags = QueryWindows31FilesMigration( Win31SystemStartEvent );

  71. if (Win31MigrationFlags != 0) {

  72. SynchronizeWindows31FilesAndWindowsNTRegistry( Win31SystemStartEvent,

  73. Win31MigrationFlags,

  74. NULL,

  75. NULL

  76. );

  77. InitSystemFontInfo();

  78. }

  79. }

  80.  
  81. #ifdef _X86_

  82.  
  83. //

  84. // Do OS/2 Subsystem boot-time migration.

  85. // Only applicable to x86 builds.

  86. //

  87.  
  88. Os2MigrationProcedure();

  89.  
  90. #endif

  91.  
  92.  
  93. //

  94. // Load those pesky fonts:

  95. //

  96.  
  97. hFontThread = StartLoadingFonts();

  98.  
  99.  
  100.  
  101. //

  102. // Check if we need to run setup's GUI repair code

  103. //

  104.  
  105. CheckForRepairRequest ();

  106. }



(17)。

 
  1. //

  2. // Kick off a thread to watch the system dlls, initialize winmm, etc

  3. //

  4.  
  5. if (g_Console) {

  6. hThread = CreateThread (NULL, 0, (LPTHREAD_START_ROUTINE) InitializeSlowStuff,

  7. NULL, 0, &dwThreadID);

  8.  
  9. if (hThread) {

  10. SetThreadPriority (hThread, THREAD_PRIORITY_IDLE);

  11. CloseHandle (hThread);

  12. } else {

  13. InitializeSlowStuff (NULL);

  14. }

  15. }


 

 
  1. DWORD InitializeSlowStuff (LPVOID dummy)

  2. {

  3.  
  4. //

  5. // initialize the dll hell watcher

  6. //

  7.  
  8. Sleep(100);

  9.  
  10. //

  11. // call the winmm guys so they can start their message window

  12. // and whatever else they need.

  13. //

  14.  
  15. #if !defined(_WIN64_LOGON)

  16.  
  17. try

  18. {

  19. waveOutGetNumDevs();

  20. }

  21. except ( EXCEPTION_EXECUTE_HANDLER )

  22. {

  23. DebugLog(( DEB_ERROR, "Failed to initialize winmm, %x\n", GetExceptionCode() ));

  24. }

  25.  
  26.  
  27. #endif

  28.  
  29. if (SfcInitProt( SFC_REGISTRY_DEFAULT, SFC_DISABLE_NORMAL, SFC_SCAN_NORMAL, SFC_QUOTA_DEFAULT, NULL, NULL )) {

  30. #if DBG

  31. ExitProcess( EXIT_SYSTEM_PROCESS_ERROR );

  32. #endif

  33. }

  34.  
  35.  
  36.  
  37. return 0;

  38. }

  39.  


 

(18)载入GINA模块

(18、1)根据是是安全模式,如果是那么就直接从"%SystemRoot%\\system32\\msgina.dll"载入msgina.dll;

如果不是,那么从注册表GinaDLL字段中读取自定义DLL。

 
  1. if ( pTerm->SafeMode )

  2. {

  3. ExpandEnvironmentStringsW(

  4. TEXT("%SystemRoot%\\system32\\msgina.dll"),

  5. pszGinaName,

  6. MAX_PATH );

  7. }

  8. else

  9. {

  10. GetProfileString(

  11. APPLICATION_NAME,

  12. GINA_KEY,

  13. TEXT("msgina.dll"),

  14. pszGinaName,

  15. MAX_PATH);

  16.  
  17. }

(18、2)

LoadGinaDll负责载入msgina.dll库,并获得其中的接口地址;

然后调用pWlxNegotiate

 
  1. if (!LoadGinaDll (pTerm, pszGinaName)) {

  2. DebugLog((DEB_TRACE_INIT, "Failed to load gina\n"));

  3. ExitProcess( EXIT_GINA_ERROR );

  4. }



 
(19)初始化SAS

 
  1. //

  2. // Initialize the secure attention sequence

  3. //

  4.  
  5. if (!SASInit(pTerm))

  6. {

  7. DebugLog((DEB_TRACE_INIT, "Failed to create sas window\n"));

  8. ExitProcess( EXIT_SAS_WINDOW_ERROR );

  9. }

 

SASInit做了以下几件事:

(19、1)创建SAS窗口

 
  1. pTerm->hwndSAS = CreateWindowEx(0L, szSASClass, TEXT("SAS window"),

  2. WS_OVERLAPPEDWINDOW,

  3. 0, 0, 0, 0,

  4. NULL, NULL, g_hInstance, NULL);


(19、2)把终端指针存在窗口数据中

 
  1. //

  2. // Store our terminal pointer in the window user data

  3. //

  4.  
  5. SetWindowLongPtr(pTerm->hwndSAS, GWLP_USERDATA, (LONG_PTR)pTerm);

(19、3)把这个窗口设置为我们通知屏保和用户注销的窗口

 
  1. //

  2. // Register this window with windows so we get notified for

  3. // screen-saver startup and user log-off

  4. //

  5.  
  6. if (!SetLogonNotifyWindow(pTerm->hwndSAS)) {

  7. DebugLog((DEB_ERROR, "Failed to set logon notify window"));

  8. return FALSE;

  9. }


(20)初始化GPO支持和自动回滚支持

 
  1. InitializeGPOSupport( pTerm );

  2.  
  3. InitializeAutoEnrollmentSupport ();

  4.  
  5. WlAddInternalNotify(

  6. PokeComCtl32,

  7. WL_NOTIFY_LOGOFF,

  8. FALSE,

  9. FALSE,

  10. TEXT("Reset ComCtl32"),

  11. 15 );


(21)进入主循环   (重点介绍)

此函数做的内容就是与GINA的交互。

 
  1. //

  2. // Main loop

  3. //

  4.  
  5. MainLoop (pTerm);

(21、1)  初始化GINA DLL库

 
  1. //

  2. // Initialize the gina dll

  3. //

  4.  
  5. if (!InitializeGinaDll(pTerm))

  6. {

  7. DebugLog((DEB_ERROR, "InitializeGinaDll failed\n"));

  8. return;

  9. }


 

 
  1. BOOL

  2. InitializeGinaDll(PTERMINAL pTerm)

  3. {

  4.  
  5. #if DBG

  6. if (TEST_FLAG(GinaBreakFlags, BREAK_INITIALIZE))

  7. {

  8. DebugLog((DEB_TRACE, "About to call WlxInitialize\n"));

  9.  
  10.  
  11. DebugBreak();

  12. }

  13. #endif

  14.  
  15.  
  16. //

  17. // Perversely, this may not return. The GINA may in fact call SASNotify

  18. // immediately, so update the state before we go in:

  19. //

  20.  
  21. pTerm->WinlogonState = Winsta_NoOne;

  22. DebugLog((DEB_TRACE_STATE, "InitGina: State is %d %s\n", Winsta_NoOne, GetState(Winsta_NoOne)));

  23.  
  24. if (!pTerm->Gina.pWlxInitialize(pTerm->pWinStaWinlogon->lpWinstaName,

  25. pTerm,

  26. NULL,

  27. (PVOID) &WlxDispatchTable,

  28. &pTerm->Gina.pGinaContext))


pWlxInitialize函数有五个参数:

A、winsta名字,[IN],由winlogon传GINA;

B、pTerm,[IN], PTERMINAL类型。 GINA调用分发表中的函数时,第一个参数为它。

C、NULL,[IN]

D、&WlxDispatchTable, 最重要的。[IN],GINA将调用从winlogon得到的分发表中的函数。

我们将在第二点中讲到。

 
  1. WLX_DISPATCH_VERSION_1_3 WlxDispatchTable = {

  2. WlxUseCtrlAltDel,

  3. WlxSetContextPointer,

  4. WlxSasNotify,

  5. WlxSetTimeout,

  6. WlxAssignShellProtection,

  7. WlxMessageBox,

  8. WlxDialogBox,

  9. WlxDialogBoxParam,

  10. WlxDialogBoxIndirect,

  11. WlxDialogBoxIndirectParam,

  12. WlxSwitchDesktopToUser,

  13. WlxSwitchDesktopToWinlogon,

  14. WlxChangePasswordNotify,

  15. WlxGetSourceDesktop,

  16. WlxSetReturnDesktop,

  17. WlxCreateUserDesktop,

  18. WlxChangePasswordNotifyEx,

  19. WlxCloseUserDesktop,

  20. WlxSetOption,

  21. WlxGetOption,

  22. WlxWin31Migrate,

  23. WlxQueryClientCredentials,

  24. WlxQueryInetConnectorCredentials,

  25. WlxDisconnect,

  26. WlxQueryTerminalServicesData

  27. };



E、&pTerm->Gina.pGinaContext, [OUT],接收GINA返回的GINA类的类指针。

(21、2)如果是控制台,那么等待各种服务、MUP、DS启动

 
  1. //

  2. // Wait for various services to start

  3. //

  4.  
  5. if (g_Console) {

  6. WaitForServices(pTerm);

  7. }


等待的服务有:"SamSs"、TEXT("NETLOGON")、TEXT("RpcSs")、WaitForMUP (120000);、WaitForDS (120000);

在等待过程中有窗口提示。

 
  1. VOID WaitForServices(

  2. PTERMINAL pTerm

  3. )

  4. {

  5.  
  6. HANDLE hDsReindexEvent ;

  7. ULONG SamWaitTime = 15000 ;

  8.  
  9. if ( pTerm->SafeMode )

  10. {

  11. SamWaitTime = 120000 ;

  12. }

  13.  
  14. StatusMessage(FALSE, 0, IDS_STATUS_SYSTEM_STARTUP );

  15. WaitForServiceToStart( TEXT("SamSs"), SamWaitTime);

  16.  
  17. if ( pTerm->SafeMode )

  18. {

  19. //

  20. // In safe mode, no sense waiting for services that

  21. // are disabled to start.

  22. //

  23.  
  24. return;

  25. }

  26. hDsReindexEvent = OpenEvent( SYNCHRONIZE,

  27. FALSE,

  28. L"NTDS.IndexRecreateEvent" );

  29.  
  30. if ( hDsReindexEvent ) {

  31. StatusMessage( FALSE, 0, IDS_STATUS_DS_REINDEX );

  32.  
  33. WaitForSingleObject( hDsReindexEvent, INFINITE );

  34.  
  35. CloseHandle( hDsReindexEvent );

  36. }

  37.  
  38. //

  39. // Wait for the network to start

  40. //

  41.  
  42. StatusMessage (FALSE, 0, IDS_STATUS_NET_START);

  43. WaitForServiceToStart (SERVICE_NETLOGON, 120000);

  44.  
  45. StatusMessage (TRUE, 0, IDS_STATUS_RPCSS_START);

  46. WaitForServiceToStart (TEXT("RpcSs"), 120000);

  47.  
  48. StatusMessage (TRUE, 0, IDS_STATUS_MUP_START);

  49. WaitForMUP (120000);

  50.  
  51. StatusMessage (TRUE, 0, IDS_STATUS_DS_START);

  52. WaitForDS (120000);

  53. }

  54.  

(21、3)启动profile映射API

 
  1. //

  2. // Start profile mapping APIs

  3. //

  4.  
  5. if (g_Console) {

  6. InitializeProfileMappingApi();

  7. }


(21、4)做网络访问向导事务

 
  1. //

  2. // Do Net Access Wizard stuff

  3. //

  4.  
  5. if ( CheckForNetAccessWizard(pTerm) )

  6. {

  7. // Reboot is required

  8. pTerm->LastGinaRet = (DWORD) WLX_SAS_ACTION_SHUTDOWN_REBOOT;

  9. return;

  10. }


 

 
  1. BOOL

  2. CheckForNetAccessWizard (

  3. PTERMINAL pTerm

  4. )

  5. {

  6. BOOL fReboot = FALSE;

  7. HKEY hkeyWinlogon = NULL;

  8. LONG lResult;

  9. DWORD dwSize, dwType;

  10. ULONG uWizardType = NAW_NETID; // NAW_NETID is not valid

  11. HINSTANCE hNetPlWiz;

  12. LPNETACCESSWIZARD pfnNetAccessWiz;

  13. DWORD dwWin9xUpgrade = 0;

  14.  
  15. //

  16. // Do we have a post setup wizard entry? Or a Win9x upgrade entry?

  17. //

  18.  
  19. if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, WINLOGON_KEY,

  20. 0, KEY_READ | KEY_WRITE, &hkeyWinlogon) == ERROR_SUCCESS) {

  21.  
  22. dwSize = sizeof(uWizardType);

  23.  
  24. RegQueryValueEx (

  25. hkeyWinlogon,

  26. L"RunNetAccessWizard",

  27. NULL,

  28. &dwType,

  29. (LPBYTE) &uWizardType,

  30. &dwSize

  31. );

  32.  
  33. dwSize = sizeof(dwWin9xUpgrade);

  34.  
  35. RegQueryValueEx (

  36. hkeyWinlogon,

  37. L"SetWin9xUpgradePasswords",

  38. NULL,

  39. &dwType,

  40. (LPBYTE) &dwWin9xUpgrade,

  41. &dwSize

  42. );

  43.  
  44. }

  45.  
  46. //

  47. // check the wizard type, if its != NAW_NETID then we assume that we should

  48. // be starting the wizard for post setup.

  49. //

  50.  
  51. if ( uWizardType != NAW_NETID || dwWin9xUpgrade )

  52. {

  53. //

  54. // Wait on the font loading thread here, so we don't inadvertantly re-enter

  55. // the stuff in user that gets confused.

  56. //

  57.  
  58. if ( hFontThread )

  59. {

  60. WaitForSingleObject( hFontThread, INFINITE );

  61. CloseHandle( hFontThread );

  62. hFontThread = NULL;

  63. }

  64.  
  65. //

  66. // wait for SAM to get its act together...

  67. //

  68.  
  69. PAWaitForSamService();

  70.  
  71.  
  72. //

  73. // Get rid of the status UI so we don't overlap

  74. //

  75.  
  76. RemoveStatusMessage(TRUE);

  77.  
  78.  
  79. if ( !dwWin9xUpgrade ) {

  80. //

  81. // lets load the network account wizard and set it off

  82. //

  83.  
  84. hNetPlWiz = LoadLibrary(L"netplwiz.dll");

  85. if ( hNetPlWiz )

  86. {

  87. pfnNetAccessWiz = (LPNETACCESSWIZARD)GetProcAddress(hNetPlWiz, "NetAccessWizard");

  88. if ( pfnNetAccessWiz )

  89. (*pfnNetAccessWiz)(NULL, uWizardType, &fReboot);

  90.  
  91. FreeLibrary(hNetPlWiz);

  92.  
  93. //

  94. // The wizard has completed, remove the value that

  95. // caused it to run

  96. //

  97.  
  98. RegDeleteValue (hkeyWinlogon, L"RunNetAccessWizard");

  99. }

  100.  
  101. } else {

  102. //

  103. // Launch the Win9x upgrade password UI

  104. //

  105.  
  106. SetWin9xUpgradePasswords (pTerm);

  107. }

  108. }

  109.  
  110. if ( hkeyWinlogon ) {

  111. RegCloseKey (hkeyWinlogon);

  112. }

  113.  
  114. return fReboot;

  115. }

  116.  


(21、5)
发送启动通知。

 
  1. //

  2. // Send the Startup notification

  3. //

  4.  
  5. WlWalkNotifyList( pTerm, WL_NOTIFY_STARTUP );


WlWalkNotifyList会漫步通知列表,根据指定的标志调用操作。

 
  1. VOID

  2. WlWalkNotifyList(

  3. PTERMINAL Terminal,

  4. DWORD Operation

  5. )

  6. {

  7. PLIST_ENTRY Scan ;

  8. PWLP_NOTIFICATION_OBJECT Notify;

  9. PWINDOWSTATION pWS = Terminal->pWinStaWinlogon ;

  10. HANDLE ThreadHandle ;

  11. DWORD tid ;

  12. BOOL bAsync;

  13. DWORD OperationMask ;

  14. PWLP_NOTIFY_BOOTSTRAP Boot ;

  15. WLP_NOTIFY_BOOTSTRAP LocalBoot ;

  16.  
  17.  
  18. OperationMask = WLP_NOTIFY_FLAG( Operation );

  19.  
  20. LockNotifyList();

  21.  
  22. Scan = NotifyList.Flink ;

  23.  
  24. while ( Scan != &NotifyList )

  25. {

  26. Notify = CONTAINING_RECORD( Scan, WLP_NOTIFICATION_OBJECT, List );

  27.  
  28. if ( Notify->Type & OperationMask )

  29. {

  30.  
  31. //

  32. // Match. Now, check the options.

  33. //

  34.  
  35. if ( (Notify->Dll == NULL) &&

  36. ((Notify->Type & WLP_NOTIFY_INTERNAL) == 0) )

  37. {

  38. //

  39. // Not snapped yet. Snap it:

  40. //

  41.  
  42. if ( !WlpSnapNotifyDll( Notify, OperationMask ) )

  43. {

  44. //

  45. // Couldn't snap this one. Remove it and continue on:

  46. //

  47.  
  48. Scan = Scan->Flink ;

  49.  
  50. RemoveEntryList( &Notify->List );

  51.  
  52. WlpDeleteNotificationObject( Notify );

  53.  
  54. continue;

  55. }

  56. }

  57.  
  58. Boot = (PWLP_NOTIFY_BOOTSTRAP) LocalAlloc( LMEM_FIXED,

  59. sizeof( WLP_NOTIFY_BOOTSTRAP ) );

  60.  
  61. if ( Boot == NULL )

  62. {

  63. Scan = Scan->Flink ;

  64.  
  65. continue;

  66. }

  67.  
  68. bAsync = ( Notify->Type & WLP_NOTIFY_ASYNCHRONOUS ) ? TRUE : FALSE;

  69.  
  70. if ( ( Operation == WL_NOTIFY_LOGOFF ) ||

  71. ( Operation == WL_NOTIFY_SHUTDOWN ) )

  72. {

  73. bAsync = FALSE;

  74. }

  75.  
  76. Boot->Notify = Notify ;

  77. Boot->Terminal = Terminal ;

  78. Boot->Operation = Operation ;

  79.  
  80. ThreadHandle = CreateThread( 0, 0,

  81. WlpExecuteNotify,

  82. Boot,

  83. 0,

  84. &tid );

  85.  
  86. if ( ThreadHandle )

  87. {

  88. if ( !bAsync )

  89. {

  90. DWORD WaitStatus ;

  91. DWORD TotalWait = 0 ;

  92.  
  93. while ( TotalWait < Notify->dwMaxWait )

  94. {

  95. WaitStatus = WaitForSingleObject( ThreadHandle, 5000 );

  96.  
  97. if ( WaitStatus == STATUS_WAIT_0 )

  98. {

  99. break;

  100. }

  101.  
  102. TotalWait += 5 ;

  103.  
  104. }

  105. }

  106.  
  107. CloseHandle( ThreadHandle );

  108. }

  109. else

  110. {

  111. LocalFree( Boot );

  112. }

  113. }

  114.  
  115. Scan = Scan->Flink ;

  116.  
  117. }

  118.  
  119. UnlockNotifyList();

  120. }


(21、6)进入循环

(21、6、1)

DealWithAutochkLogs();

DealWithAutochkLogs会枚举当前磁盘,并偿试着去处理它找到的任何的AUTOCHK logs。

 
  1.  
  2. do {

  3. if ( GetDriveTypeW( pwszVolumeName ) == DRIVE_FIXED ) {

  4. wcscpy( pwszBootExFile, pwszVolumeName );

  5. wcscat( pwszBootExFile, L"bootex.log" );

  6.  
  7. if ( TransferAutochkLogToEventLogIfAvailable( pwszBootExFile )) {

  8. DeleteFileW( pwszBootExFile );

  9. }

  10. }

  11.  
  12. } while ( FindNextVolume( h, pwszVolumeName, MAX_PATH + 1 ));


TransferAutochkLogToEventLogIfAvailable的原理是从找到的文件中读取事件列表,并通过API  ReportEvent报错winlogon的事件。

(21、6、2)从注册表中获得verbose状态。

 QueryVerboseStatus();

(21、6、3) 调用GINA的pWlxRemoveStatusMessage移除状态提示对话框。

 RemoveStatusMessage(TRUE);
 
  1. VOID

  2. RemoveStatusMessage(

  3. BOOL bForce

  4. )

  5. {

  6.  
  7. //

  8. // Check if the gina is ready

  9. //

  10.  
  11. if (!g_pTerminals || !g_pTerminals->Gina.pGinaContext) {

  12. return;

  13. }

  14.  
  15.  
  16. //

  17. // Remove the status message under these conditions:

  18. //

  19. // 1) We are not in verbose status message mode

  20. // 2) We are in verbose status message mode and bForce is true

  21. //

  22.  
  23. if (!g_bVerboseStatus || (g_bVerboseStatus && bForce)) {

  24. g_pTerminals->Gina.pWlxRemoveStatusMessage(g_pTerminals->Gina.pGinaContext);

  25. }

  26.  
  27. }

(21、6、4)如果Term的winlogon状态是Winsta_NoOne,那么

 

A、设置对话框的当前超时时间;

WlxSetTimeout(pTerm, TIMEOUT_NONE);
 
  1. BOOL

  2. WINAPI

  3. WlxSetTimeout(

  4. HANDLE hWlx,

  5. DWORD Timeout

  6. )

  7. {

  8. PTERMINAL pTerm;

  9.  
  10. if (pTerm = VerifyHandle(hWlx))

  11. {

  12. if ((pTerm->WinlogonState == Winsta_NoOne_Display) ||

  13. (pTerm->WinlogonState == Winsta_Locked_Display) )

  14. {

  15. if (Timeout)

  16. {

  17. SetLastErrorEx(ERROR_INVALID_PARAMETER, SLE_ERROR);

  18. return(FALSE);

  19. }

  20. }

  21. pTerm->Gina.cTimeout = Timeout;

  22. TimeoutUpdateTopTimeout( Timeout );

  23. return(TRUE);

  24. }

  25.  
  26. SetLastErrorEx(ERROR_INVALID_HANDLE, SLE_ERROR);

  27. return(FALSE);

  28.  
  29. }

  30.  


B、调用GINA的pWlxDisplaySASNotice接口来显示SAS通知;即:

C、如果我们获得用户logooff通知,那么意味着我们已经关机,一个远程的关机会发生,它已经在sysshut.c里启动。

 
  1. //

  2. if (pTerm->SasType == WLX_SAS_TYPE_USER_LOGOFF)

  3. {

  4. //

  5. // We are *done*

  6. //

  7.  
  8. DebugLog(( DEB_TRACE_STATE, "Received Logoff, setting state to %s\n",

  9. GetState(Winsta_Shutdown) ));

  10.  
  11. break;

  12. }


D、如果我们获得一个超时的SAS,那么

 

(21、6、5) 偿试登陆

 WlxResult = LogonAttempt(pTerm);

A、为新的登陆创建一个登陆SID

pLogonSid = CreateLogonSid(NULL);

CreateLogonid做了以下事情:

首先,产生一个本地的唯一的ID;

Status = NtAllocateLocallyUniqueId(&Luid);

然后,为SID分配空间;

 
  1. Length = RtlLengthRequiredSid(SECURITY_LOGON_IDS_RID_COUNT);

  2.  
  3. Sid = (PSID)Alloc(Length);

最后,将唯一的ID来填充SID空间。

 
  1. RtlInitializeSid(Sid, &gSystemSidAuthority, SECURITY_LOGON_IDS_RID_COUNT);

  2.  
  3. ASSERT(SECURITY_LOGON_IDS_RID_COUNT == 3);

  4.  
  5. *(RtlSubAuthoritySid(Sid, 0)) = SECURITY_LOGON_IDS_RID;

  6. *(RtlSubAuthoritySid(Sid, 1 )) = Luid.HighPart;

  7. *(RtlSubAuthoritySid(Sid, 2 )) = Luid.LowPart;


B、如果不是控制台。

gpfnWinStationSetInformation是winsta.dll中的接口。

 
  1. if (!g_Console) {

  2. //

  3. // BUGBUG Disabling winstations should be in terminal server and not in

  4. // the registry. WinStationNotifyLogon() can return an error status noting this, and

  5. // winlogon can call the GINA to put up the message.

  6. //

  7. if (GetProfileInt(APPLICATION_NAME, WINSTATIONS_DISABLED, 0) == 1) {

  8. TimeoutDialogBoxParam(

  9. pTerm,

  10. NULL,

  11. (LPTSTR)IDD_DISABLED,

  12. NULL,

  13. LogonDisabledDlgProc,

  14. 0,

  15. TIMEOUT_NONE

  16. );

  17.  
  18. WlxResult = WLX_SAS_ACTION_LOGOFF;

  19. pTerm->WinlogonState = Winsta_NoOne;

  20. DeleteLogonSid(pLogonSid);

  21. return(WlxResult);

  22. }

  23.  
  24. //

  25. // Send a signal to the communications channel that

  26. // we are going into Secure-Attention-Sequence mode.

  27. //

  28. gpfnWinStationSetInformation(

  29. SERVERNAME_CURRENT,

  30. LOGONID_CURRENT,

  31. WinStationSecureDesktopEnter,

  32. NULL,

  33. 0);

  34. }


C、如果终端有log out,那么告诉gina忽略自动登陆。

 
  1. //

  2. // if this terminal has had a log out, then tell the gina to ignore auto logon

  3. //

  4.  
  5. if ( pTerm->IgnoreAutoLogon )

  6. Options |= WLX_OPTION_IGNORE_AUTO_LOGON;

D、设置登陆框的时间为120S。然后调用GINA的pWlxLoggedOutSAS函数。

 
  1. WlxSetTimeout(pTerm, 120);

  2.  
  3. WlxResult = pTerm->Gina.pWlxLoggedOutSAS(pGinaContext,

  4. pTerm->SasType,

  5. &pWS->LogonId,

  6. pLogonSid,

  7. &Options,

  8. &hToken,

  9. &MprInfo,

  10. &pProfileInfo );


E、

 
  1. //

  2. // Signal the communications channel that we are no longer

  3. // in SAS mode.

  4. //

  5. if( !g_Console ) {

  6. gpfnWinStationSetInformation(

  7. SERVERNAME_CURRENT,

  8. LOGONID_CURRENT,

  9. WinStationSecureDesktopExit,

  10. NULL,

  11. 0);

  12. }


F、如果登陆成功

保存用户名,保存Domain;如果是终端服务器,那么调用MultiUserLogonAttempt。

 
  1. if (WlxResult == WLX_SAS_ACTION_LOGON)

  2. {

  3. if (MprInfo.pszUserName)

  4. {

  5. pWS->UserName = AllocAndDuplicateString(MprInfo.pszUserName);

  6. }

  7.  
  8. if ( MprInfo.pszDomain )

  9. {

  10. pWS->Domain = AllocAndDuplicateString( MprInfo.pszDomain );

  11. }

  12.  
  13. if (g_IsTerminalServer)

  14. {

  15. WlxResult = MultiUserLogonAttempt(pTerm, &MprInfo, hToken);

  16. }

  17. }


MultiUserLogonAttempt过程介绍:

F、1   获得计算机名字

 if (!GetComputerNameW(ComputerName, &Length)) {

F、2  如果GINA没有查询USERCONFIG数据,我们需要。

 
  1. Error = QueryTerminalServicesDataWorker(pTerm, pMprInfo->pszUserName,

  2. pMprInfo->pszDomain);

QueryTerminalServicesDataWorker做了以下事情:

F、2、1 获得计算机名

 if (!GetComputerNameW(ComputerName, &Length))

F、2、2 获得DcNameBuffer。方法有两种:根据计算机名;根据API DsGetDcName获得Domain控制信息,然后从中抽取出来。

F、2、3 地入regapi.dll库,并获得接口RegUserConfigQuery、RegDefaultUserConfigQueryW,调用接口。


F、3 如果在检索USERCONFIG时发生错误或者远程登陆WinStations被禁用时,检查错误

 
  1. if (Error != ERROR_SUCCESS || pTerm->MuGlobals.UserConfig.fLogonDisabled) {

  2. if (Error != ERROR_SUCCESS) {

  3. DebugLog((DEB_ERROR,"MultiUserLogonAttempt: Error from user "

  4. "config query %u\n", Error));

  5. }

  6. if (pTerm->MuGlobals.UserConfig.fLogonDisabled) {

  7. DebugLog((DEB_TRACE,"MultiUserLogonAttempt: fLogonDisabled\n"));

  8. }

  9.  
  10. HandleFailedLogon(pTerm, NULL, (NTSTATUS)ERROR_CTX_LOGON_DISABLED, 0,

  11. pMprInfo->pszUserName, pMprInfo->pszDomain);

  12. return WLX_SAS_ACTION_LOGOFF;

  13. }


F、4  发送domain、username和token给terminalServer

 
  1. if (!gpfnWinStationNotifyLogon((BOOLEAN)TestTokenForAdmin(hToken), hToken, pMprInfo->pszDomain,

  2. pMprInfo->pszUserName, L"", 0, &pTerm->MuGlobals.UserConfig))


F、5 发送服务名字、用户名、用户domain给客户端

 
  1. gpfnWinStationSetInformation( SERVERNAME_CURRENT,

  2. LOGONID_CURRENT,

  3. WinStationClientData,

  4. pInfo,

  5. TotalSize );

F、6  如果不是控制台会话,那么处理WinStation回调

F、7  重新连接会话

 
  1. WlxResult = WLX_SAS_ACTION_LOGON;

  2. if (CtxConnectSession(pTerm)) {

  3. WlxResult = WLX_SAS_ACTION_RECONNECTED;

  4. }

  5. else {

  6. // Tell terminal service that a new terminal user session has been

  7. // created.

  8. if ((!g_Console) && (NULL != gpfnWinStationNotifyNewSession)) {

  9. if (!gpfnWinStationNotifyNewSession(

  10. SERVERNAME_CURRENT,

  11. LOGONID_CURRENT))

  12. {

  13. HandleFailedLogon(pTerm, NULL, (NTSTATUS)GetLastError(), 0,

  14. pMprInfo->pszUserName, pMprInfo->pszDomain);

  15. WlxResult = WLX_SAS_ACTION_LOGOFF;

  16. }

  17. }

  18. }


 


 

 

G、如果没有登陆成功

删除前面得到的SID

 
  1. if (WlxResult != WLX_SAS_ACTION_LOGON)

  2. {

  3. DebugLog((DEB_TRACE_STATE, "LogonAttempt: Resetting state to %s\n", GetState(Winsta_NoOne)));

  4.  
  5. pTerm->WinlogonState = Winsta_NoOne;

  6.  
  7. DeleteLogonSid(pLogonSid);

  8.  
  9. if (pWS->UserName)

  10. {

  11. FreeAndNull(pWS->UserName);

  12. }

  13.  
  14. if (pWS->Domain)

  15. {

  16. FreeAndNull(pWS->Domain);

  17. }

  18.  
  19. return(WlxResult);

  20. }


H、如果pWS->Domain存在,那么从注册表中读出用户名对应的键值是否存在,如果存在则

H、1  调用API  ImpersonateLoggedOnUser .

 

 
  1. if (lResult == ERROR_SUCCESS) {

  2. //

  3. // Ask the user if they want to merge their profiles

  4. //

  5.  
  6. ImpersonateLoggedOnUser (hToken);

  7.  
  8. lResult = MergeProfiles (pTerm);

  9.  
  10. RevertToSelf();

  11.  
  12. if (lResult == ERROR_SUCCESS || lResult == ERROR_CONTINUE) {

  13. //

  14. // The profile was remapped or split into separate profiles

  15. //

  16.  
  17. RegDeleteValue (hKey, pWS->UserName);

  18.  
  19. if (lResult != ERROR_CONTINUE) {

  20. i = WLX_SAS_ACTION_NONE;

  21. }

  22.  
  23. } else if (lResult == ERROR_REQUEST_ABORTED) {

  24. //

  25. // User cancelled the UI

  26. //

  27.  
  28. // nothing needed

  29.  
  30. } else {

  31. //

  32. // An error occurred (code in lResult)

  33. //

  34.  
  35. i = WLX_SAS_ACTION_LOGOFF;

  36. }

  37. }


ImpersonateLoggedOnUser它让调用线程模仿登陆用户的security context。

H、2  然后调用MergeProfiles来询问是否要合并他们的本地和domain配置。

如果要合并,那么:

把鼠标变为等待,然后又调用ImpersonateLoggedOnUser让调用线程模仿登陆用户的security context,并调用RemapAndMoveUser(找不到定义。)

如果返回值是不允许登陆,那么就做循环弹出对话框来判断,直到允许。

 
  1. //

  2. // User has chosen to merge their profile

  3. //

  4.  
  5. hOldCursor = SetCursor (LoadCursor(NULL, IDC_WAIT));

  6. ImpersonateLoggedOnUser (pWS->hToken);

  7.  
  8. b = RemapAndMoveUser (NULL, 0, LocalUser, DomainUser);

  9. Error = GetLastError();

  10.  
  11. RevertToSelf();

  12. SetCursor (hOldCursor);

  13.  
  14. if (!b && Error == ERROR_ACCESS_DENIED) {

  15. do {

  16. //

  17. // Prompt for administrator credentials, then try again.

  18. //

  19.  
  20. PwArgs.pTerm = pTerm;

  21.  
  22. rc = WlxDialogBoxParam(pTerm,

  23. g_hInstance,

  24. (LPTSTR)IDD_ADMIN_PW,

  25. NULL,

  26. AdminPwDlgProc,

  27. (LPARAM) &PwArgs

  28. );

  29.  
  30. if (rc != IDOK) {

  31. return ERROR_CANCELLED;

  32. }

  33.  
  34. hOldCursor = SetCursor (LoadCursor(NULL, IDC_WAIT));

  35. ImpersonateLoggedOnUser (PwArgs.hToken);

  36.  
  37. b = RemapAndMoveUser (NULL, REMAP_PROFILE_KEEPLOCALACCOUNT, LocalUser, DomainUser);

  38. Error = GetLastError();

  39.  
  40. RevertToSelf();

  41. SetCursor (hOldCursor);

  42.  
  43. if (Error == ERROR_ACCESS_DENIED) {

  44. //

  45. // If non-admin credentials were entered, then try again

  46. //

  47.  
  48. LoadString (NULL, IDS_REMAP_PROFILE_RETRY, StackMsgBuf, ARRAYSIZE(StackMsgBuf));

  49. WlxMessageBox (pTerm, NULL, StackMsgBuf, Caption, MB_OK);

  50. }

  51.  
  52. } while (Error == ERROR_ACCESS_DENIED);

  53.  
  54. LogoffIfError = TRUE;

  55. }


H、3  根据H、2返回的结果进行注册表记录,并返回值。

 

I、如果有用户登陆成功,那么以下是有的:

MprLogonNotify通知logon的证书管理

 
  1. //

  2. // Okay, someone logged on. This, this is interesting.

  3. //

  4.  
  5. MprLogonNotify(

  6. pTerm,

  7. NULL,

  8. MprInfo.pszUserName,

  9. MprInfo.pszDomain,

  10. MprInfo.pszPassword,

  11. MprInfo.pszOldPassword,

  12. &pWS->LogonId,

  13. &pWS->LogonScripts);

  14.  
  15. DestroyMprInfo(&MprInfo);


I、1   NoNeedToNotify根据注册表判断是否需要通知,如果不需要直接返回

 
  1. if (NoNeedToNotify()) {

  2. DebugLog((DEB_TRACE_MPR, "MprLogonNotify - skipping notification - only one provider\n"));

  3. *MprLogonScripts = NULL;

  4. return(DLG_SUCCESS);

  5. }

 

I、2   RtlCreateEnvironment 创建通知数据的环境(RtlCreateEnvironment在MSDN中并没找到它的定义);

         通过SetCommonNotifyVariables将窗口句柄、用户名、密码、Domain、LogonID放到通知数据的环境里。

 

 
  1. RtlZeroMemory( &NotifyData, sizeof( NotifyData ) );

  2. //

  3. // Set up the environment variables that we will use to pass

  4. // information to notify process

  5. //

  6.  
  7. Status = RtlCreateEnvironment(

  8. TRUE,

  9. &NotifyData.Env );

  10.  
  11. if ( !NT_SUCCESS( Status ) )

  12. {

  13. return DLG_FAILURE ;

  14. }

  15.  
  16.  
  17. if (!SetCommonNotifyVariables(

  18. &NotifyData.Env,

  19. hwndOwner,

  20. Name,

  21. Domain,

  22. Password,

  23. OldPassword

  24. )) {

  25. return(DLG_FAILURE);

  26. }

  27.  
  28. if (!SetLogonNotifyVariables(&NotifyData.Env, LogonId)) {

  29. return(DLG_FAILURE);

  30. }


 

 

 


SetCommonNotifyVariables里只调用了SetNotifyVariable,通过对SetNotifyVariable指定不同的类型把不同的数据加到环境数据中。

SetNotifyVariable就是调用了系统的API  RtlSetEnvironmentVariable(它同样在MSDN中找不到):

 

 
  1. BOOL

  2. SetNotifyVariable(

  3. PVOID * Env,

  4. LPWSTR Variable,

  5. LPWSTR Value

  6. )

  7. {

  8. NTSTATUS Status ;

  9. UNICODE_STRING Var ;

  10. UNICODE_STRING Val ;

  11.  
  12. if ( !Variable )

  13. {

  14. return FALSE ;

  15. }

  16.  
  17. if ( !Value )

  18. {

  19. return TRUE ;

  20. }

  21.  
  22. RtlInitUnicodeString( &Var, Variable );

  23. RtlInitUnicodeString( &Val, Value );

  24. Status = RtlSetEnvironmentVariable(

  25. Env,

  26. &Var,

  27. &Val);

  28.  
  29. return NT_SUCCESS( Status );

  30. }

  31.  


 

I、3  初始化我们的通知数据结构

 
  1. NotifyData.pTerm = pTerm;

  2. NotifyData.ReturnBuffer = NULL;


I、4    更新windowsstation 锁,这样我们的通知能被启动。


 

 
  1. //

  2. // Update windowstation lock so mpnotify can start.

  3. //

  4.  
  5. if ( pTerm->pWinStaWinlogon->ActiveDesktop == Desktop_Winlogon )

  6. {

  7. UnlockWindowStation(pTerm->pWinStaWinlogon->hwinsta);

  8. FastSetWinstaSecurity(pTerm->pWinStaWinlogon, FALSE);

  9. }


 

I、5   创建对话框,这样它将初始化通知并等待完成

 
  1. //

  2. // Create the dialog that will initiate the notify and wait

  3. // for it to complete

  4. //

  5.  
  6. Result = WlxDialogBoxParam( pTerm,

  7. g_hInstance,

  8. (LPTSTR)IDD_CONTROL,

  9. hwndOwner,

  10. MprNotifyDlgProc,

  11. (LPARAM)&NotifyData);


I、6 重新锁住windowstation

 
  1. //

  2. // Re-lock the windowstation.

  3. //

  4.  
  5. if ( pTerm->pWinStaWinlogon->ActiveDesktop == Desktop_Winlogon )

  6. {

  7. LockWindowStation(pTerm->pWinStaWinlogon->hwinsta);

  8. }

  9.  
  10. RtlDestroyEnvironment( NotifyData.Env );

  11.  
  12. if ( NotifyData.SAS != 0 )

  13. {

  14. DebugLog(( DEB_TRACE_MPR, "SAS interruption - reposting SAS\n" ));

  15. EnableSasMessages( NULL, pTerm );

  16. SASRouter( pTerm, (DWORD) NotifyData.SAS );

  17. }


 

J、 等待字体载入线程

 
  1. //

  2. // Wait on the font loading thread here, so we don't inadvertantly re-enter

  3. // the stuff in user that gets confused.

  4. //

  5.  
  6. if ( hFontThread )

  7. {

  8. WaitForSingleObject( hFontThread, INFINITE );

  9.  
  10. CloseHandle( hFontThread );

  11.  
  12. hFontThread = NULL;

  13.  
  14. }

hFontThread为(16)中调用的StartLoadingFonts函数创建的载入字体的线程。

K、切换用户到已登陆的用户

SecurityChangeUser(pTerm, hToken, NULL, pLogonSid, TRUE);


L、如果从GINA的pWlxLoggedOutSAS返回的Options中有WLX_LOGON_OPT_NO_PROFILE属性,那么:

 
  1. if (!TEST_FLAG(Options, WLX_LOGON_OPT_NO_PROFILE))

  2. {

  3. if (pProfileInfo) {

  4. if (pProfileInfo->pszProfile)

  5. {

  6. pWS->UserProfile.ProfilePath =

  7. AllocAndExpandEnvironmentStrings(pProfileInfo->pszProfile);

  8. LocalFree(pProfileInfo->pszProfile);

  9. }

  10. else

  11. {

  12. pWS->UserProfile.ProfilePath = NULL;

  13. }

  14.  
  15. if (pProfileInfo->dwType >= WLX_PROFILE_TYPE_V2_0) {

  16. if (pProfileInfo->pszPolicy)

  17. {

  18. pWS->UserProfile.PolicyPath =

  19. AllocAndDuplicateString(pProfileInfo->pszPolicy);

  20.  
  21. LocalFree(pProfileInfo->pszPolicy);

  22. }

  23. else

  24. {

  25. pWS->UserProfile.PolicyPath = NULL;

  26. }

  27.  
  28. if (pProfileInfo->pszNetworkDefaultUserProfile)

  29. {

  30. pWS->UserProfile.NetworkDefaultUserProfile =

  31. AllocAndDuplicateString(pProfileInfo->pszNetworkDefaultUserProfile);

  32.  
  33. LocalFree(pProfileInfo->pszNetworkDefaultUserProfile);

  34. }

  35. else

  36. {

  37. pWS->UserProfile.NetworkDefaultUserProfile = NULL;

  38. }

  39.  
  40. if (pProfileInfo->pszServerName)

  41. {

  42. pWS->UserProfile.ServerName =

  43. AllocAndDuplicateString(pProfileInfo->pszServerName);

  44.  
  45. LocalFree(pProfileInfo->pszServerName);

  46. }

  47. else

  48. {

  49. pWS->UserProfile.ServerName = NULL;

  50. }

  51.  
  52. if (pProfileInfo->pszEnvironment)

  53. {

  54. pWS->UserProfile.Environment =

  55. AllocAndDuplicateStrings(pProfileInfo->pszEnvironment);

  56.  
  57. LocalFree(pProfileInfo->pszEnvironment);

  58. }

  59. else

  60. {

  61. pWS->UserProfile.Environment = NULL;

  62. }

  63. } else {

  64. pWS->UserProfile.PolicyPath = NULL;

  65. pWS->UserProfile.NetworkDefaultUserProfile = NULL;

  66. pWS->UserProfile.ServerName = NULL;

  67. pWS->UserProfile.Environment = NULL;

  68. }

  69. }

  70.  
  71. DebugLog((DEB_TRACE_PROFILE, "Using initial profile path of %ws\n", pWS->UserProfile.ProfilePath));

  72.  
  73. LocalFree(pProfileInfo);

  74.  
  75.  
  76. //

  77. // Load profile, set environment variables, etc.

  78. //

  79.  
  80. if (SetupUserEnvironment(pTerm))

  81. {

  82. OpenIniFileUserMapping(pTerm);

  83.  
  84. uh = ImpersonateUser(&pWS->UserProcessData, NULL);

  85.  
  86. SetWindowStationUser(pWS->hwinsta, &pWS->LogonId,

  87. pWS->UserProcessData.UserSid,

  88. RtlLengthSid(pWS->UserProcessData.UserSid));

  89.  
  90. StopImpersonating(uh);

  91.  
  92. //

  93. // Update the window station lock so that apps can start.

  94. //

  95.  
  96. UnlockWindowStation(pWS->hwinsta);

  97. LockWindowStation(pWS->hwinsta);

  98.  
  99. //

  100. // allocate floppies and CDRoms (if so configured)

  101. //

  102.  
  103. RmvAllocateRemovableMedia( pLogonSid );

  104.  
  105. //

  106. // Start a task for the network provider notify

  107. //

  108. if ( NetworkProviderEvent )

  109. {

  110. RegisterWaitForSingleObject(

  111. &pWS->UserProfile.NetworkProviderTask,

  112. NetworkProviderEvent,

  113. NetworkProviderTask,

  114. pTerm,

  115. INFINITE,

  116. 0);

  117.  
  118. }

  119. }

  120. else

  121. {

  122. //

  123. // Whoops, something went wrong. we *must* log the user

  124. // out. We do this by passing LOGOFF back to mainloop.

  125. //

  126.  
  127. WlxResult = WLX_SAS_ACTION_LOGOFF;

  128. }

  129. }


 

(21、6、6) 接下来就是根据LogonAttempt返回的结果做业务处理

A、如果是非控制台

 
  1. if (!g_Console) {

  2. if ( ((WlxResult == WLX_SAS_ACTION_RECONNECTED) || (WlxResult == WLX_SAS_ACTION_LOGOFF)) ) {

  3. //

  4. // LogonAttempt returns WLX_SAS_ACTION_RECONNECTED in the case that we

  5. // reconnected to an existing session. In this case, we simply want

  6. // to exit the while loop and then exit WinLogon.

  7. // We also want to exit winlogon when a user hits Cancel on the Logon dialog.

  8. // In this case LogonAttempt will return WLX_SAS_ACTION_LOGOFF

  9. //

  10.  
  11. break;

  12.  
  13. } else if ((WlxResult == WLX_SAS_ACTION_NONE) && (pTerm->SasType == WLX_SAS_TYPE_CTRL_ALT_DEL) ) {

  14.  
  15. //

  16. // If the Logon dialog is idle for 120 seconds (LOGON_TIMEOUT)

  17. // exit the session.

  18. //

  19. DbgPrint("Timed out!!. Session %d will be terminated\n",NtCurrentPeb()->SessionId);

  20. break;

  21.  
  22. }

  23. }

B、如果是注销,那么调用DeleteRasConnections删除RAS连接

 
  1. if ( WlxResult == WLX_SAS_ACTION_LOGOFF )

  2. {

  3. DeleteRasConnections(pTerm);

  4. WlxResult = WLX_SAS_ACTION_NONE ;

  5. }


 

 
  1. BOOL

  2. DeleteRasConnections(

  3. PTERMINAL pTerm

  4. )

  5. {

  6. HANDLE ImpersonationHandle;

  7. SC_HANDLE hServiceMgr, hService;

  8. SERVICE_STATUS status;

  9. RASCONN rasconn;

  10. LPRASCONN lprasconn = &rasconn;

  11. DWORD i, dwErr, dwcb, dwc;

  12. BOOL bRet;

  13. PRASENUMCONNECTIONSW pRasEnumConnectionsW;

  14. PRASHANGUPW pRasHangUpW;

  15. BOOL FreeThatRasConn = FALSE;

  16. PWINDOWSTATION pWS = pTerm->pWinStaWinlogon;

  17.  
  18.  
  19. if ( GetProfileInt( WINLOGON, KEEP_RAS_AFTER_LOGOFF, 0 ) )

  20. {

  21. return( TRUE );

  22. }

  23.  
  24. //

  25. // Determine whether the rasman service is running.

  26. //

  27.  
  28. hServiceMgr = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);

  29.  
  30. if ( hServiceMgr == NULL )

  31. {

  32. DebugLog((DEB_ERROR, "Unable to object service controller, %d\n", GetLastError()));

  33. return( FALSE );

  34. }

  35.  
  36. hService = OpenService(

  37. hServiceMgr,

  38. RASMAN_SERVICE_NAME,

  39. SERVICE_QUERY_STATUS);

  40.  
  41. if (hService == NULL)

  42. {

  43. CloseServiceHandle(hServiceMgr);

  44. DebugLog((DEB_TRACE, "rasman not started, nothing to tear down\n"));

  45. return( TRUE );

  46. }

  47.  
  48. bRet = QueryServiceStatus( hService, &status );

  49.  
  50. CloseServiceHandle(hService);

  51.  
  52. CloseServiceHandle(hServiceMgr);

  53.  
  54. if (! bRet )

  55. {

  56. //

  57. // Service in bad state, get out of here...

  58. //

  59.  
  60. return( TRUE );

  61. }

  62.  
  63. if (status.dwCurrentState != SERVICE_RUNNING)

  64. {

  65. //

  66. // Service is not running

  67. //

  68.  
  69. return( TRUE );

  70.  
  71. }

  72.  
  73. //

  74. // Load the RASAPI DLL so we can make it do stuff

  75. //

  76.  
  77. if ( !hRasApi )

  78. {

  79. hRasApi = LoadLibrary( RASAPI32 );

  80. if ( !hRasApi )

  81. {

  82. return( FALSE );

  83. }

  84. }

  85.  
  86. pRasEnumConnectionsW = (PRASENUMCONNECTIONSW) GetProcAddress(

  87. hRasApi,

  88. "RasEnumConnectionsW" );

  89.  
  90. pRasHangUpW = (PRASHANGUPW) GetProcAddress(

  91. hRasApi,

  92. "RasHangUpW" );

  93.  
  94. if ( (!pRasEnumConnectionsW) ||

  95. (!pRasHangUpW) )

  96. {

  97. return( FALSE );

  98. }

  99.  
  100.  
  101.  
  102. //

  103. // Impersonate the user

  104. //

  105.  
  106. ImpersonationHandle = ImpersonateUser(&pWS->UserProcessData, NULL);

  107.  
  108. if (ImpersonationHandle == NULL) {

  109. DebugLog((DEB_ERROR, "DeleteNetworkConnections : Failed to impersonate user\n"));

  110. return(FALSE);

  111. }

  112.  
  113. //

  114. // Enumerate the current RAS connections.

  115. //

  116.  
  117.  
  118. lprasconn->dwSize = sizeof (RASCONN);

  119.  
  120. dwcb = sizeof (RASCONN);

  121.  
  122. dwc = 1;

  123.  
  124. dwErr = pRasEnumConnectionsW(lprasconn, &dwcb, &dwc);

  125.  
  126. if (dwErr == ERROR_BUFFER_TOO_SMALL)

  127. {

  128. lprasconn = LocalAlloc(LPTR, dwcb);

  129.  
  130. FreeThatRasConn = TRUE;

  131.  
  132. if ( !lprasconn )

  133. {

  134. return( FALSE );

  135. }

  136.  
  137. lprasconn->dwSize = sizeof (RASCONN);

  138.  
  139. dwErr = pRasEnumConnectionsW(lprasconn, &dwcb, &dwc);

  140. if (dwErr)

  141. {

  142. if ( FreeThatRasConn )

  143. {

  144. LocalFree( lprasconn );

  145. }

  146.  
  147. return( FALSE );

  148. }

  149. }

  150. else if (dwErr)

  151. {

  152. return( FALSE );

  153. }

  154.  
  155. //

  156. // cycle through the connections, and kill them

  157. //

  158.  
  159.  
  160. for (i = 0; i < dwc; i++)

  161. {

  162. DebugLog((DEB_TRACE, "Hanging up connection to %ws\n",

  163. lprasconn[i].szEntryName));

  164.  
  165. (VOID) pRasHangUpW( lprasconn[i].hrasconn );

  166. }

  167.  
  168. if ( FreeThatRasConn )

  169. {

  170. LocalFree( lprasconn );

  171. }

  172.  
  173. //

  174. // Revert to being 'ourself'

  175. //

  176.  
  177. if (!StopImpersonating(ImpersonationHandle)) {

  178. DebugLog((DEB_ERROR, "DeleteNetworkConnections : Failed to revert to self\n"));

  179. }

  180.  
  181. return( TRUE );

  182. }

  183.  
  184.  


B、1  如果是从ini文件中读出是保持RAS连接,那么直接返回;

B、2  打开“RASMAN“服务,通过获得服务句柄查询服务状态。

B、3  载入RASAPI32.DLL,获得RasEnumConnectionsW、RasHangUpW接口;

B、4   模拟用户模式;

  ImpersonationHandle = ImpersonateUser(&pWS->UserProcessData, NULL);

B、5 调用B、3得到的接口枚举RAS连接,然后将RAS连接断开。

B、6 退出模拟模式;

 
  1. if (!StopImpersonating(ImpersonationHandle)) {

  2. DebugLog((DEB_ERROR, "DeleteNetworkConnections : Failed to revert to self\n"));

  3. }


C、如果是没有登陆成功,那么:

 
  1. if (WlxResult == WLX_SAS_ACTION_NONE)

  2. {

  3. //

  4. // If we got a user logoff notify, that means that WE HAVE ALREADY

  5. // SHUT DOWN. A remote shutdown has taken place, and it has been

  6. // started by sysshut.c.

  7. //

  8. if (pTerm->SasType == WLX_SAS_TYPE_USER_LOGOFF)

  9. {

  10. //

  11. // We are *done*

  12. //

  13.  
  14. DebugLog(( DEB_TRACE_STATE, "Got logoff during logon, setting to %s\n",

  15. GetState(Winsta_Shutdown) ));

  16.  
  17. pTerm->WinlogonState = Winsta_Shutdown;

  18.  
  19. break;

  20. }

  21. //

  22. // If we got a time out (meaning a screensaver timeout

  23. // occurred during the logon prompt, then the prompt should be dead,

  24. // but we'll hit here

  25. //

  26. if (pTerm->SasType == WLX_SAS_TYPE_SCRNSVR_TIMEOUT)

  27. {

  28. //

  29. // run the screen saver

  30. //

  31. ScreenSaverResult = DoScreenSaver(pTerm, FALSE);

  32.  
  33. if (ScreenSaverResult < 0)

  34. {

  35. //

  36. // This means that a SAS other than activity cancelled

  37. // the screen saver, such as a GINA specific one.

  38. // In this case, drop on through to the logonattempt,

  39. // since the current sas is in pTerm.

  40. //

  41.  
  42. NOTHING ;

  43.  
  44. }

  45. else

  46. {

  47. if ( (ScreenSaverResult == 0) &&

  48. (pTerm->SasType == WLX_SAS_TYPE_USER_LOGOFF) )

  49. {

  50. //

  51. // Shutdown during the screen saver.

  52. //

  53.  
  54. DebugLog(( DEB_TRACE_STATE, "Received Logoff during screensaver, setting state to %s\n",

  55. GetState(Winsta_Shutdown) ));

  56.  
  57. pTerm->WinlogonState = Winsta_Shutdown;

  58.  
  59. break;

  60.  
  61. }

  62.  
  63. if ( ScreenSaverResult == WLX_SAS_ACTION_LOGOFF )

  64. {

  65. break;

  66. }

  67.  
  68. }

  69.  
  70. //

  71. // We're already at WlxResult == NONE, and State == NoOne,

  72. // so we can just continue

  73. //

  74.  
  75. }

  76.  
  77. //

  78. // Make sure that we're back to NoOne:

  79. //

  80.  
  81. pTerm->WinlogonState = Winsta_NoOne;

  82.  
  83. continue;

  84. }


 

C、1  如果是退出

C、2  如果是超时,要求进入屏保

C、3 否则continue,继续偿试登陆。

D、如果RAS是睡眠或是关机

 

 
  1. {

  2. SuspendComputer((WlxResult == WLX_SAS_ACTION_SHUTDOWN_HIBERNATE) ? TRUE : FALSE,

  3. (WlxResult == WLX_SAS_ACTION_SHUTDOWN_SLEEP2) ? TRUE : FALSE);

  4.  
  5. pTerm->WinlogonState = Winsta_NoOne;

  6. WlxResult = WLX_SAS_ACTION_NONE;

  7. continue;

  8. }

  9.  
  10. if (IsShutdown(WlxResult))

  11. {

  12. pTerm->LastGinaRet = WlxResult;

  13. DebugLog((DEB_TRACE_STATE, "Setting state to %d (%s)\n",

  14. Winsta_WaitForShutdown, GetState(Winsta_WaitForShutdown)));

  15. pTerm->WinlogonState = Winsta_WaitForShutdown;

  16. break;

  17. }

 

E、如果是登陆成功

 
  1. if (WlxResult == WLX_SAS_ACTION_LOGON)

  2. {

  3.  
  4. #ifndef _WIN64

  5.  
  6. //

  7. // Since someone logged on notify the nddeagnt thread that

  8. // it can impersonate the logged on user

  9. //

  10.  
  11. if (g_hwndAppDesktopThread != NULL) {

  12. PostMessage(g_hwndAppDesktopThread,

  13. WM_USERCHANGED,

  14. (WPARAM)g_hwndAppDesktopThread,

  15. (LPARAM)pTerm->pWinStaWinlogon->hToken);

  16. }

  17. #endif // _WIN64

  18.  
  19. WlWalkNotifyList( pTerm, WL_NOTIFY_LOGON );

  20.  
  21. if (DoStartShell(pTerm))

  22. {

  23. DebugLog(( DEB_TRACE_STATE, "Setting state to LoggedOnUser\n" ));

  24.  
  25. pTerm->WinlogonState = Winsta_LoggedOnUser ;

  26.  
  27. WlWalkNotifyList( pTerm, WL_NOTIFY_POSTSHELL );

  28.  
  29. //

  30. // now wait for the user to take an action (like generating the SAS)

  31. //

  32.  
  33. WlxResult = BlockWaitForUserAction(pTerm);

  34.  
  35. if (WlxResult == WLX_SAS_ACTION_FORCE_LOGOFF)

  36. {

  37. WaitForForceLogoff(NULL, pTerm);

  38.  
  39. WlxResult = WLX_SAS_ACTION_LOGOFF;

  40.  
  41. }

  42. }

  43. else

  44. {

  45. WlxResult = WLX_SAS_ACTION_LOGOFF;

  46. }

  47. }

E、1  给netdde 代理的主窗口发送WM_USERCHANGED消息,并把登陆成功的token发过去。

E、2  发送通知WL_NOTIFY_LOGON

WlWalkNotifyList会漫步通知列表,根据指定的标志调用操作。

E、3  启动terminate的Shell  (重点)

DoStartShell 完成启动任务,如果成功,那么发送WL_NOTIFY_POSTSHELL通知,

 
  1. if (DoStartShell(pTerm))

  2. {

  3. DebugLog(( DEB_TRACE_STATE, "Setting state to LoggedOnUser\n" ));

  4.  
  5. pTerm->WinlogonState = Winsta_LoggedOnUser ;

  6.  
  7. WlWalkNotifyList( pTerm, WL_NOTIFY_POSTSHELL );

  8.  
  9. //

  10. // now wait for the user to take an action (like generating the SAS)

  11. //

  12.  
  13. WlxResult = BlockWaitForUserAction(pTerm);

  14.  
  15. if (WlxResult == WLX_SAS_ACTION_FORCE_LOGOFF)

  16. {

  17. WaitForForceLogoff(NULL, pTerm);

  18.  
  19. WlxResult = WLX_SAS_ACTION_LOGOFF;

  20.  
  21. }

  22. }

  23. else

  24. {

  25. WlxResult = WLX_SAS_ACTION_LOGOFF;

  26. }


 

 

 
  1. BOOL

  2. DoStartShell(

  3. PTERMINAL pTerm

  4. )

  5. {

  6. HANDLE hImp;

  7. BOOL StartStatus ;

  8. HINSTANCE hInstMPR;

  9. PFNRESTORENETCON pfnRestoreNetCon;

  10. PVOID pNewEnvironment;

  11. WCHAR szDesktop[MAX_PATH];

  12. PWINDOWSTATION pWS = pTerm->pWinStaWinlogon;

  13. UINT ErrorMode ;

  14.  
  15.  
  16. RemoveStatusMessage(FALSE);

  17. (void) DisplayPreShellLogonMessages(pTerm);

  18.  
  19. //

  20. // If not logging in as Guest, System or Administrator then check for

  21. // migration of Windows 3.1 configuration inforation.

  22. //

  23.  
  24. if (szAdminName[ 0 ] == TEXT('\0'))

  25. {

  26. LoadString(NULL, IDS_ADMIN_ACCOUNT_NAME, szAdminName, ARRAYSIZE(szAdminName));

  27. }

  28.  
  29.  
  30. if (g_Console) {

  31.  
  32. if (!IsUserAGuest(pWS) &&

  33. _wcsicmp(pWS->UserName, szAdminName)

  34. )

  35. {

  36. Windows31Migration(pTerm);

  37. }

  38.  
  39. //

  40. // Setup the user's power profile. For Hydra, default power settings for

  41. // physical console's user take effect.

  42. //

  43.  
  44. StatusMessage(TRUE, 0, IDS_STATUS_POWER_PROFILE);

  45. SetPowerProfile(pTerm);

  46.  
  47. }

  48.  
  49.  
  50.  
  51.  
  52. //

  53. // Further initialize multimedia and play the user's logon sound

  54. //

  55.  
  56. StatusMessage(TRUE, 0, IDS_STATUS_PLAY_LOGON_SOUND);

  57.  
  58. {

  59. BOOL fBeep;

  60.  
  61. hImp = ImpersonateUser(&pWS->UserProcessData, NULL);

  62.  
  63. __try { WinmmLogon(g_Console); }

  64. __except (EXCEPTION_EXECUTE_HANDLER) { NOTHING; }

  65.  
  66. if (OpenIniFileUserMapping(pTerm))

  67. {

  68. __try

  69. {

  70. //

  71. // Migrate driver settings

  72. //

  73. MigrateAllDrivers();

  74.  
  75. MigrateSoundEvents();

  76. }

  77. __except (EXCEPTION_EXECUTE_HANDLER)

  78. {

  79. NOTHING ;

  80. }

  81.  
  82. //

  83. // Whenever a user logs in, have WINMM.DLL check if there

  84. // are any sound events within the [SOUNDS] section of

  85. // CONTROL.INI that haven't been ported into HKCU/AppEvents.

  86. // If there are, migrate those schemes to their new home.

  87. // This must be done before the upcoming PlaySound() call,

  88. // as PlaySound() uses the HKCU/AppEvents schemes-listing

  89. // to resolve an SND_ALIAS_ID request.

  90. //

  91.  
  92. if (!SystemParametersInfo(SPI_GETBEEP, 0, &fBeep, FALSE)) {

  93. // Failed to get hold of beep setting. Should we be

  94. // noisy or quiet? We have to choose one value...

  95. fBeep = TRUE;

  96. }

  97.  
  98. if (fBeep) {

  99. PlaySoundAsync( pTerm, (LPCTSTR) SND_ALIAS_SYSTEMSTART );

  100.  
  101. //(*(g_PlaySound))((LPCSTR)SND_ALIAS_SYSTEMSTART,

  102. // NULL,

  103. // SND_ALIAS_ID | SND_ASYNC | SND_NODEFAULT);

  104. }

  105.  
  106.  
  107. CloseIniFileUserMapping(pTerm);

  108. }

  109.  
  110. StopImpersonating(hImp);

  111.  
  112. }

  113.  
  114.  
  115. StatusMessage(TRUE, 0, IDS_STATUS_RESTORE_NET);

  116.  
  117.  
  118. //

  119. // Restore the user's network connections

  120. //

  121. if ( pTerm->SafeMode == FALSE )

  122. {

  123. if (OpenHKeyCurrentUser(pTerm->pWinStaWinlogon))

  124. {

  125. if (OpenIniFileUserMapping(pTerm))

  126. {

  127. if (hImp = ImpersonateUser(&pWS->UserProcessData, NULL))

  128. {

  129. if (hInstMPR = LoadLibrary(TEXT("mpr.dll")))

  130. {

  131. pfnRestoreNetCon = (PFNRESTORENETCON)GetProcAddress (hInstMPR,

  132. "WNetRestoreConnectionW");

  133.  
  134. if (pfnRestoreNetCon)

  135. {

  136. WCHAR szUserName[100];

  137.  
  138. if (pWS->UserName) {

  139. szUserName[0] = TEXT('\0');

  140. GetEnvironmentVariableW (USERNAME_VARIABLE, szUserName, 100);

  141. SetEnvironmentVariableW (USERNAME_VARIABLE, pWS->UserName);

  142. }

  143.  
  144. pfnRestoreNetCon(NULL, NULL);

  145.  
  146. if (pWS->UserName) {

  147. if (szUserName[0] != TEXT('\0'))

  148. SetEnvironmentVariableW (USERNAME_VARIABLE, szUserName);

  149. else

  150. SetEnvironmentVariableW (USERNAME_VARIABLE, NULL);

  151. }

  152. }

  153.  
  154. FreeLibrary (hInstMPR);

  155. }

  156.  
  157. StopImpersonating(hImp);

  158. }

  159.  
  160. CloseIniFileUserMapping(pTerm);

  161. }

  162.  
  163. CloseHKeyCurrentUser(pTerm->pWinStaWinlogon);

  164. }

  165. }

  166.  
  167.  
  168.  
  169. //

  170. // Notify the clients

  171. //

  172.  
  173. WlWalkNotifyList( pTerm, WL_NOTIFY_STARTSHELL );

  174.  
  175. RemoveStatusMessage(TRUE);

  176.  
  177. WlxSetTimeout(pTerm, 120);

  178.  
  179. pNewEnvironment = CopyEnvironment(pWS->UserProcessData.pEnvironment);

  180.  
  181. wsprintfW (szDesktop, L"%s\\%s", pWS->lpWinstaName,

  182. APPLICATION_DESKTOP_NAME);

  183.  
  184. #if DBG

  185. if (TEST_FLAG(GinaBreakFlags, BREAK_ACTIVATE))

  186. {

  187. DebugLog((DEB_TRACE, "About to call WlxActivateUserShell(%#x, %ws, %ws, %#x)\n",

  188. pTerm->Gina.pGinaContext, szDesktop,

  189. pWS->LogonScripts, NULL));

  190. DebugBreak();

  191. }

  192. #endif

  193.  
  194. ErrorMode = SetErrorMode( pTerm->ErrorMode );

  195.  
  196. StartStatus = pTerm->Gina.pWlxActivateUserShell(pTerm->Gina.pGinaContext,

  197. szDesktop,

  198. pWS->LogonScripts,

  199. pNewEnvironment) ;

  200.  
  201. SetErrorMode( ErrorMode );

  202.  
  203. return StartStatus ;

  204. }


F、使能SAS消息,然后激活winlogon桌面。

 
  1. EnableSasMessages(NULL, pTerm);

  2.  
  3. SetActiveDesktop(pTerm, Desktop_Winlogon);


G、

 
  1. if ( ( pTerm->WinlogonState == Winsta_Shutdown ) &&

  2. ( !g_Console ) )

  3. {

  4. DebugLog(( DEB_ERROR, "Winstation already shutdown?\n" ));

  5. DebugBreak();

  6. break;

  7. }

  8.  
  9.  
  10. Logoff(pTerm, WlxResult);

  11.  
  12. if (WlxResult == WLX_SAS_ACTION_LOGOFF)

  13. {

  14. pTerm->WinlogonState = Winsta_NoOne;

  15. DebugLog((DEB_TRACE, "WlxResult was logoff, so beginning loop again\n"));

  16. DebugLog((DEB_TRACE_STATE, "State set to %s\n", GetState(Winsta_NoOne)));

  17. WlxResult = WLX_SAS_ACTION_NONE;

  18. }

  19.  
  20. //

  21. // Notify the GINA that the user is logged off

  22. //

  23.  
  24. #if DBG

  25. if (TEST_FLAG(GinaBreakFlags, BREAK_LOGOFF))

  26. {

  27. DebugLog((DEB_TRACE, "About to call WlxLogoff(%x)\n",

  28. pTerm->Gina.pGinaContext));

  29. DebugBreak();

  30. }

  31. #endif

  32. pTerm->Gina.pWlxLogoff(pTerm->Gina.pGinaContext);

  33.  
  34. //

  35. // For non-Console WinStations we exit WinLogon after

  36. // one logon/logoff iteration.

  37. //

  38. if ( !g_Console ) {

  39.  
  40. break;

  41.  
  42. }

  43.  
  44. #ifndef _WIN64

  45.  
  46. //

  47. // Don't start the NetDDE thread on sessions

  48. //

  49. if (g_Console) {

  50. //

  51. // start the application thread. Note: no win64 support

  52. // for NetDDE (hooray!)

  53. //

  54.  
  55. StartAppDesktopThread(pTerm);

  56. }

  57. #endif

  58.  
  59. //

  60. // Toggle the winsta lock on and off. This clears the openlock, and

  61. // sets the switchlock, allowing services to start, but no one can

  62. // switch the active desktop.

  63. //

  64.  
  65. UnlockWindowStation(pTerm->pWinStaWinlogon->hwinsta);

  66. LockWindowStation(pTerm->pWinStaWinlogon->hwinsta);

  67.  
  68. #if DBG

  69. if ((WlxResult == WLX_SAS_ACTION_NONE) ||

  70. (WlxResult == WLX_SAS_ACTION_LOGON) ||

  71. (WlxResult == WLX_SAS_ACTION_SHUTDOWN) ||

  72. (WlxResult == WLX_SAS_ACTION_SHUTDOWN_REBOOT) ||

  73. (WlxResult == WLX_SAS_ACTION_SHUTDOWN_POWER_OFF) ||

  74. (WlxResult == WLX_SAS_ACTION_SHUTDOWN_SLEEP) ||

  75. (WlxResult == WLX_SAS_ACTION_SHUTDOWN_SLEEP2) ||

  76. (WlxResult == WLX_SAS_ACTION_SHUTDOWN_HIBERNATE) )

  77. {

  78. continue;

  79. }

  80.  
  81. DebugLog((DEB_TRACE, "WlxResult not acceptible value: %d\n", WlxResult));

  82. DebugLog((DEB_TRACE, "Resetting to WLX_SAS_ACTION_NONE\n"));

  83. WlxResult = WLX_SAS_ACTION_NONE;

  84. #endif


 

 

 

 二、SAS窗口处理函数

 


 

 


 

 三、重点介绍WlxDispatchTable

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值