/*++ Copyright (c) 1998 Microsoft Corporation Module Name: sclgntfy.cxx Abstract: Notification dll for secondary logon service Author: Praerit Garg (Praeritg) Revision History: --*/ #ifdef __cplusplus extern "C" { #endif #include #include #include #ifdef __cplusplus } #endif #include #include #include #include "seclogon.h" #include #include "sclgntfy.hxx" // // Some helpful tips about winlogon's notify events // // 1) The logoff and shutdown notifications are always done // synchronously regardless of the Asynchronous registry entry. // // 2) If you need to spawn child processes, you have to use // CreateProcessAsUser() otherwise the process will start // on winlogon's desktop (not the user's) // // 3) The logon notification comes before the user's network // connections are restored. If you need the user's persisted // net connections, use the StartShell event. // // 4) Don't put any UI up during either screen saver event. // These events are intended for background processing only. // HINSTANCE g_hDllInstance=NULL; #define NOTIFY_PATH TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon\\Notify\\sclgntfy") BOOL SlpCreateProcessWithLogon( ULONG LogonIdLowPart, LONG LogonIdHighPart ); extern "C" void *__cdecl _alloca(size_t); DWORD SetupLocalRPCSecurity(handle_t hRPCBinding) { CHAR szDomainName[128]; CHAR szName[128]; DWORD cbDomainName; DWORD cbName; DWORD dwResult; PSID pSid = NULL; RPC_SECURITY_QOS SecurityQOS; SID_IDENTIFIER_AUTHORITY SidAuthority = SECURITY_NT_AUTHORITY; SID_NAME_USE SidNameUse; // We're doing LRPC -- we need to get the account name of the service to do mutual auth if (!AllocateAndInitializeSid(&SidAuthority, 1, SECURITY_LOCAL_SYSTEM_RID, 0, 0, 0, 0, 0, 0, 0, &pSid)) { dwResult = GetLastError(); goto error; } cbName = sizeof(szName); cbDomainName = sizeof(szDomainName); if (!LookupAccountSidA(NULL, pSid, szName, &cbName, szDomainName, &cbDomainName, &SidNameUse)) { dwResult = GetLastError(); goto error; } // Specify quality of service parameters. SecurityQOS.ImpersonationType = RPC_C_IMP_LEVEL_IMPERSONATE; // the server will need to impersonate us SecurityQOS.Version = RPC_C_SECURITY_QOS_VERSION; SecurityQOS.Capabilities = RPC_C_QOS_CAPABILITIES_MUTUAL_AUTH; // we need mutual auth SecurityQOS.IdentityTracking = RPC_C_QOS_IDENTITY_STATIC; // calls go to the server under the identity that created the binding handle dwResult = RpcBindingSetAuthInfoExA(hRPCBinding, (unsigned char *)szName, RPC_C_AUTHN_LEVEL_PKT_PRIVACY, RPC_C_AUTHN_WINNT, NULL, 0, &SecurityQOS); if (RPC_S_OK != dwResult) goto error; dwResult = ERROR_SUCCESS; error: if (NULL != pSid) { FreeSid(pSid); } return dwResult; } BOOL SlpCreateProcessWithLogon( ULONG LogonIdLowPart, LONG LogonIdHighPart ) /*++ Routine Description: Arguments: Return Value: --*/ { BOOL fOk = FALSE; DWORD dwResult; LPWSTR pwszBinding = NULL; RPC_BINDING_HANDLE hRPCBinding = NULL; SECL_BLOB sbNULL = { 0, NULL }; SECL_SLI sli; SECL_SLRI slri; SECL_STRING ssNULL = { 0, 0, NULL }; ZeroMemory(&sli, sizeof(sli)); ZeroMemory(&slri, sizeof(slri)); __try { sli.ulLogonIdLowPart = LogonIdLowPart; sli.lLogonIdHighPart = LogonIdHighPart; sli.ulProcessId = GetCurrentProcessId(); sli.ssUsername = ssNULL; sli.ssDomain = ssNULL; sli.ssPassword = ssNULL; sli.ssApplicationName = ssNULL; sli.ssCommandLine = ssNULL; sli.ulCreationFlags = 0; sli.sbEnvironment = sbNULL; sli.ssCurrentDirectory = ssNULL; sli.ssTitle = ssNULL; sli.ssDesktop = ssNULL; // Make the RPC call: // dwResult = RpcStringBindingCompose (NULL, (unsigned short *)L"ncalrpc", NULL, (unsigned short *)wszSeclogonSharedProcEndpointName, NULL, (unsigned short **)&pwszBinding); if (RPC_S_OK != dwResult) { __leave; } dwResult = RpcBindingFromStringBinding((unsigned short *)pwszBinding, &hRPCBinding); if (0 != dwResult) { __leave; } dwResult = SetupLocalRPCSecurity(hRPCBinding); if (ERROR_SUCCESS != dwResult) { __leave; } __try { SeclCreateProcessWithLogonW (hRPCBinding, &sli, &slri); } __except(EXCEPTION_EXECUTE_HANDLER) { dwResult = RpcExceptionCode(); } if (0 != dwResult) { __leave; } fOk = (slri.ulErrorCode == NO_ERROR); // This function succeeds if the server's function succeeds if (!fOk) { // // If the server function failed, set the server's // returned eror code as this thread's error code // SetLastError(slri.ulErrorCode); } } __finally { if (NULL != pwszBinding) { RpcStringFree((unsigned short **)&pwszBinding); } if (NULL != hRPCBinding) { RpcBindingFree(&hRPCBinding); } } return(fOk); } //////////////////////////////// End Of File ///////////////////////////////// BOOL WINAPI DllMain(HANDLE hInstance, ULONG dwReason, LPVOID lpReserved) //BOOL WINAPI LibMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved) { switch (dwReason) { case DLL_PROCESS_ATTACH: { // DisableThreadLibraryCalls (hInstance); g_hDllInstance = (HINSTANCE)hInstance; } break; } return TRUE; UNREFERENCED_PARAMETER(lpReserved); } // // WLEventLogon moved to recovery.cpp // VOID WLEventLogoff (PWLX_NOTIFICATION_INFO pInfo) { TOKEN_STATISTICS TokenStats; DWORD ReturnLength; LUID LogonId; // OutputDebugString (TEXT("NOTIFY: Entering WLEventLogff.\r\n")); // // We are interested in this event. // // // We will basically call CreateProcessWithLogon // in a specially formed message such that secondary logon // service can cleanup processes associated with this // logon id. // if(GetTokenInformation(pInfo->hToken, TokenStatistics, (PVOID *)&TokenStats, sizeof(TOKEN_STATISTICS), &ReturnLength)) { LogonId.HighPart = TokenStats.AuthenticationId.HighPart; LogonId.LowPart = TokenStats.AuthenticationId.LowPart; SlpCreateProcessWithLogon( LogonId.LowPart, LogonId.HighPart ); } } VOID WLEventStartup (PWLX_NOTIFICATION_INFO pInfo) { // OutputDebugString (TEXT("NOTIFY: Entering WLEventStartup.\r\n")); UNREFERENCED_PARAMETER(pInfo); } VOID WLEventShutdown (PWLX_NOTIFICATION_INFO pInfo) { // OutputDebugString (TEXT("NOTIFY: Entering WLEventShutdown.\r\n")); UNREFERENCED_PARAMETER(pInfo); } VOID WLEventStartScreenSaver (PWLX_NOTIFICATION_INFO pInfo) { // OutputDebugString (TEXT("NOTIFY: Entering WLEventStartScreenSaver.\r\n")); UNREFERENCED_PARAMETER(pInfo); } VOID WLEventStopScreenSaver (PWLX_NOTIFICATION_INFO pInfo) { // OutputDebugString (TEXT("NOTIFY: Entering WLEventStopScreenSaver.\r\n")); UNREFERENCED_PARAMETER(pInfo); } VOID WLEventLock (PWLX_NOTIFICATION_INFO pInfo) { // OutputDebugString (TEXT("NOTIFY: Entering WLEventLock.\r\n")); UNREFERENCED_PARAMETER(pInfo); } VOID WLEventUnlock (PWLX_NOTIFICATION_INFO pInfo) { // OutputDebugString (TEXT("NOTIFY: Entering WLEventUnlock.\r\n")); UNREFERENCED_PARAMETER(pInfo); } VOID WLEventStartShell (PWLX_NOTIFICATION_INFO pInfo) { // OutputDebugString (TEXT("NOTIFY: Entering WLEventStartShell.\r\n")); UNREFERENCED_PARAMETER(pInfo); } ///////////////////////////////////////////////////////////////////////////// // DllRegisterServer - Adds entries to the system registry STDAPI DllRegisterServer(void) { HKEY hKey; LONG lResult; DWORD dwDisp, dwTemp; lResult = RegCreateKeyEx (HKEY_LOCAL_MACHINE, NOTIFY_PATH, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKey, &dwDisp); if (lResult != ERROR_SUCCESS) { return lResult; } // // save the return code for EFS registration // LONG lEfsResult = DllRegisterServerEFS(); lResult = RegSetValueEx (hKey, TEXT("Logoff"), 0, REG_SZ, (LPBYTE)TEXT("WLEventLogoff"), (lstrlen(TEXT("WLEventLogoff")) + 1) * sizeof(TCHAR)); if (lResult == ERROR_SUCCESS) { #if 0 RegSetValueEx (hKey, TEXT("Logon"), 0, REG_SZ, (LPBYTE)TEXT("WLEventLogon"), (lstrlen(TEXT("WLEventLogon")) + 1) * sizeof(TCHAR)); RegSetValueEx (hKey, TEXT("Startup"), 0, REG_SZ, (LPBYTE)TEXT("WLEventStartup"), (lstrlen(TEXT("WLEventStartup")) + 1) * sizeof(TCHAR)); RegSetValueEx (hKey, TEXT("Shutdown"), 0, REG_SZ, (LPBYTE)TEXT("WLEventShutdown"), (lstrlen(TEXT("WLEventShutdown")) + 1) * sizeof(TCHAR)); RegSetValueEx (hKey, TEXT("StartScreenSaver"), 0, REG_SZ, (LPBYTE)TEXT("WLEventStartScreenSaver"), (lstrlen(TEXT("WLEventStartScreenSaver")) + 1) * sizeof(TCHAR)); RegSetValueEx (hKey, TEXT("StopScreenSaver"), 0, REG_SZ, (LPBYTE)TEXT("WLEventStopScreenSaver"), (lstrlen(TEXT("WLEventStopScreenSaver")) + 1) * sizeof(TCHAR)); RegSetValueEx (hKey, TEXT("Lock"), 0, REG_SZ, (LPBYTE)TEXT("WLEventLock"), (lstrlen(TEXT("WLEventLock")) + 1) * sizeof(TCHAR)); RegSetValueEx (hKey, TEXT("Unlock"), 0, REG_SZ, (LPBYTE)TEXT("WLEventUnlock"), (lstrlen(TEXT("WLEventUnlock")) + 1) * sizeof(TCHAR)); RegSetValueEx (hKey, TEXT("StartShell"), 0, REG_SZ, (LPBYTE)TEXT("WLEventStartShell"), (lstrlen(TEXT("WLEventStartShell")) + 1) * sizeof(TCHAR)); #endif dwTemp = 0; lResult = RegSetValueEx (hKey, TEXT("Impersonate"), 0, REG_DWORD, (LPBYTE)&dwTemp, sizeof(dwTemp)); if (lResult == ERROR_SUCCESS) { dwTemp = 1; lResult = RegSetValueEx (hKey, TEXT("Asynchronous"), 0, REG_DWORD, (LPBYTE)&dwTemp, sizeof(dwTemp)); if (lResult == ERROR_SUCCESS) { lResult = RegSetValueEx (hKey, TEXT("DllName"), 0, REG_EXPAND_SZ, (LPBYTE)TEXT("sclgntfy.dll"), (lstrlen(TEXT("sclgntfy.dll")) + 1) * sizeof(TCHAR)); } } } RegCloseKey (hKey); // // return failure if either seclogon or EFS registration fails. // if ( lResult == ERROR_SUCCESS ) { lResult = lEfsResult; } return lResult; } ///////////////////////////////////////////////////////////////////////////// // DllUnregisterServer - Removes entries from the system registry STDAPI DllUnregisterServer(void) { RegDeleteKey (HKEY_LOCAL_MACHINE, NOTIFY_PATH); return S_OK; } BOOL pLoadResourceString( IN UINT idMsg, OUT LPTSTR lpBuffer, IN int nBufferMax, IN LPTSTR lpDefault ) { HRESULT hr; if ( lpBuffer == NULL || lpDefault == NULL ) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } if ( g_hDllInstance == NULL || !LoadString (g_hDllInstance, idMsg, lpBuffer, nBufferMax)) { hr = StringCchCopy(lpBuffer, nBufferMax, lpDefault); if (FAILED(hr)) { SetLastError(hr); return FALSE; } lpBuffer[nBufferMax-1] = L'\0'; } return TRUE; }