summaryrefslogtreecommitdiffstats
path: root/private/windows/gina/winlogon/winutil.c
diff options
context:
space:
mode:
Diffstat (limited to 'private/windows/gina/winlogon/winutil.c')
-rw-r--r--private/windows/gina/winlogon/winutil.c834
1 files changed, 834 insertions, 0 deletions
diff --git a/private/windows/gina/winlogon/winutil.c b/private/windows/gina/winlogon/winutil.c
new file mode 100644
index 000000000..b9a63bd25
--- /dev/null
+++ b/private/windows/gina/winlogon/winutil.c
@@ -0,0 +1,834 @@
+/****************************** Module Header ******************************\
+* Module Name: winutil.c
+*
+* Copyright (c) 1991, Microsoft Corporation
+*
+* Implements windows specific utility functions
+*
+* History:
+* 12-09-91 Davidc Created.
+\***************************************************************************/
+
+#include "precomp.h"
+
+#if DBG
+char * DesktopNames[] = {"Winlogon", "ScreenSaver", "Application", "[Previous]"};
+#define DbgGetDesktopName(x) (x < (sizeof(DesktopNames) / sizeof(char *)) ? DesktopNames[x] : "Unknown!")
+#endif
+
+
+HDESK
+GetActiveDesktop(
+ PWinstaDescription pWindowStation,
+ BOOL * pCloseWhenDone,
+ BOOL * pLocked)
+{
+ HDESK hDesk;
+ ActiveDesktops Desktop;
+
+ Desktop = pWindowStation->ActiveDesktop;
+ if (Desktop == -1)
+ {
+ Desktop = pWindowStation->PreviousDesktop;
+ }
+
+ switch ( Desktop )
+ {
+ case Desktop_Application:
+ hDesk = OpenInputDesktop(0, FALSE, MAXIMUM_ALLOWED);
+ *pCloseWhenDone = TRUE;
+ *pLocked = FALSE;
+ break;
+
+ case Desktop_Winlogon:
+ hDesk = pWindowStation->hdeskWinlogon;
+ *pCloseWhenDone = FALSE;
+ *pLocked = TRUE;
+ break;
+
+ case Desktop_ScreenSaver:
+ hDesk = pWindowStation->hdeskScreenSaver;
+ *pCloseWhenDone = FALSE;
+ *pLocked = FALSE;
+ break;
+
+ default:
+ DebugLog((DEB_TRACE, "Unknown desktop: %d\n", Desktop));
+ *pCloseWhenDone = FALSE;
+ hDesk = NULL;
+ *pLocked = FALSE;
+ break;
+
+ }
+
+ return(hDesk);
+}
+
+BOOL
+ToggleDesktopLock(
+ PWinstaDescription pWindowStation)
+{
+ BOOL bRet;
+
+ if (pWindowStation->Locked)
+ {
+ bRet = UnlockWindowStation( pWindowStation->hwinsta );
+ pWindowStation->Locked = FALSE;
+ }
+ else
+ {
+ bRet = LockWindowStation( pWindowStation->hwinsta );
+ pWindowStation->Locked = TRUE;
+ }
+
+ return( bRet );
+}
+
+BOOL
+SetReturnDesktop(
+ PWinstaDescription pWindowStation,
+ PWLX_DESKTOP pDesktop)
+{
+ WCHAR DesktopName[TYPICAL_STRING_LENGTH];
+ DWORD Needed;
+ PWSTR pszDesktop;
+ BOOL FreeDesktopString = FALSE;
+ HDESK hDesk;
+
+ if ( pWindowStation->ActiveDesktop == Desktop_Application )
+ {
+ return( FALSE );
+ }
+
+ if ( (pDesktop->Flags & WLX_DESKTOP_NAME) == 0 )
+ {
+ if (!GetUserObjectInformation( pDesktop->hDesktop,
+ UOI_NAME,
+ DesktopName,
+ TYPICAL_STRING_LENGTH,
+ &Needed ) )
+ {
+ if (GetLastError() != ERROR_INSUFFICIENT_BUFFER )
+ {
+ return( FALSE );
+ }
+
+ pszDesktop = LocalAlloc( LMEM_FIXED, Needed );
+
+ if ( !pszDesktop )
+ {
+ return( FALSE );
+ }
+
+ GetUserObjectInformation( pDesktop->hDesktop,
+ UOI_NAME,
+ pszDesktop,
+ Needed,
+ &Needed );
+
+ FreeDesktopString = TRUE;
+
+ }
+ else
+ {
+ pszDesktop = DesktopName;
+
+ FreeDesktopString = FALSE;
+ }
+
+ }
+ else
+ {
+ pszDesktop = pDesktop->pszDesktopName;
+
+ FreeDesktopString = FALSE;
+
+ }
+
+ hDesk = OpenDesktop( pszDesktop, 0, FALSE, MAXIMUM_ALLOWED );
+
+ if (!hDesk)
+ {
+ if (FreeDesktopString)
+ {
+ LocalFree( pszDesktop );
+ }
+ return( FALSE );
+ }
+
+ CloseDesktop( pWindowStation->hdeskPrevious );
+ pWindowStation->hdeskPrevious = hDesk;
+
+ if (FreeDesktopString)
+ {
+ LocalFree( pszDesktop );
+ }
+
+ return( TRUE );
+
+}
+
+BOOL
+SetActiveDesktop(
+ PWinstaDescription pWindowStation,
+ ActiveDesktops Desktop)
+{
+ HDESK hDesk;
+ HDESK hPrevious;
+ DWORD LengthNeeded;
+
+ if (Desktop == pWindowStation->ActiveDesktop)
+ {
+ return(TRUE);
+ }
+
+ if (pWindowStation->ActiveDesktop == Desktop_Application)
+ {
+ LockWindowStation(pWindowStation->hwinsta);
+ pWindowStation->hdeskPrevious = OpenInputDesktop(0, FALSE, MAXIMUM_ALLOWED);
+
+ if (!GetUserObjectInformation( pWindowStation->hdeskPrevious,
+ UOI_NAME,
+ pWindowStation->pszDesktop,
+ pWindowStation->DesktopLength,
+ &LengthNeeded) )
+ {
+ if (pWindowStation->DesktopLength != TYPICAL_STRING_LENGTH)
+ {
+ LocalFree( pWindowStation->pszDesktop );
+ }
+ pWindowStation->pszDesktop = LocalAlloc( LMEM_FIXED, LengthNeeded );
+ if (pWindowStation->pszDesktop)
+ {
+ pWindowStation->DesktopLength = LengthNeeded;
+
+ if (!GetUserObjectInformation( pWindowStation->hdeskPrevious,
+ UOI_NAME,
+ pWindowStation->pszDesktop,
+ pWindowStation->DesktopLength,
+ &LengthNeeded))
+ {
+ pWindowStation->pszDesktop[0] = 0;
+ }
+ }
+ else
+ {
+ pWindowStation->DesktopLength = 0;
+ }
+ }
+
+ DebugLog((DEB_TRACE, "Source desktop was %ws\n", pWindowStation->pszDesktop));
+ }
+
+ switch (Desktop)
+ {
+ case Desktop_Winlogon:
+ hDesk = pWindowStation->hdeskWinlogon;
+ break;
+ case Desktop_ScreenSaver:
+ hDesk = pWindowStation->hdeskScreenSaver;
+ break;
+ case Desktop_Application:
+ if (pWindowStation->hdeskPrevious)
+ {
+ hDesk = pWindowStation->hdeskPrevious;
+ }
+ else
+ {
+ hDesk = pWindowStation->hdeskApplication;
+ }
+ break;
+ default:
+ DebugLog((DEB_ERROR, "Error: Invalid desktop specified %d\n", Desktop));
+ return(FALSE);
+ }
+ if (SwitchDesktop(hDesk))
+ {
+ DebugLog((DEB_TRACE, "Switching desktop from %s to %s\n",
+ DbgGetDesktopName(pWindowStation->ActiveDesktop),
+ DbgGetDesktopName(Desktop) ));
+
+ pWindowStation->PreviousDesktop = pWindowStation->ActiveDesktop;
+ pWindowStation->ActiveDesktop = Desktop;
+
+ //
+ // If we're switching back to the user's desktop, then unlock the
+ // window station, so that the user can switch desktops again. Also,
+ // close our handle to the desktop. Note! Unlock before close, so
+ // that if this is the last handle to the desktop, cleanup can occur
+ // correctly.
+ //
+
+ if (pWindowStation->ActiveDesktop == Desktop_Application)
+ {
+ UnlockWindowStation(pWindowStation->hwinsta);
+ if (pWindowStation->hdeskPrevious)
+ {
+ DebugLog((DEB_TRACE, "Closing handle %x to users desktop\n", pWindowStation->hdeskPrevious));
+ CloseDesktop(pWindowStation->hdeskPrevious);
+ pWindowStation->hdeskPrevious = NULL;
+ }
+ }
+
+
+ return(TRUE);
+ }
+ DebugLog((DEB_WARN, "Could not switch desktop!\n"));
+ return(FALSE);
+}
+
+
+/***************************************************************************\
+* FUNCTION: AllocAndGetPrivateProfileString
+*
+* PURPOSE: Allocates memory for and returns pointer to a copy of the
+* specified profile string
+* The returned string should be freed using Free()
+*
+* RETURNS: Pointer to copy of profile string or NULL on failure.
+*
+* HISTORY:
+*
+* 12-Nov-92 Davidc Created.
+*
+\***************************************************************************/
+
+LPTSTR
+AllocAndGetPrivateProfileString(
+ LPCTSTR lpAppName,
+ LPCTSTR lpKeyName,
+ LPCTSTR lpDefault,
+ LPCTSTR lpFileName
+ )
+{
+ LPTSTR String;
+ LONG LengthAllocated;
+ LONG LengthCopied;
+
+ //
+ // Pick a random buffer length, if it's not big enough reallocate
+ // it and try again until it is.
+ //
+
+ LengthAllocated = TYPICAL_STRING_LENGTH;
+
+ String = Alloc(LengthAllocated * sizeof(TCHAR));
+ if (String == NULL) {
+ DebugLog((DEB_ERROR, "AllocAndGetPrivateProfileString : Failed to allocate %d bytes for string", LengthAllocated * sizeof(TCHAR)));
+ return(NULL);
+ }
+
+ while (TRUE) {
+
+ LengthCopied = GetPrivateProfileString( lpAppName,
+ lpKeyName,
+ lpDefault,
+ String,
+ LengthAllocated,
+ lpFileName
+ );
+ //
+ // If the returned value is our passed size - 1 (weird way for error)
+ // then our buffer is too small. Make it bigger and start over again.
+ //
+
+ if (LengthCopied == (LengthAllocated - 1)) {
+
+ DebugLog((DEB_TRACE, "AllocAndGetPrivateProfileString: Failed with buffer length = %d, reallocating and retrying", LengthAllocated));
+
+ LengthAllocated *= 2;
+ String = ReAlloc(String, LengthAllocated * sizeof(TCHAR));
+ if (String == NULL) {
+ DebugLog((DEB_ERROR, "AllocAndGetPrivateProfileString : Failed to reallocate %d bytes for string", LengthAllocated * sizeof(TCHAR)));
+ break;
+ }
+
+ //
+ // Go back and try to read it again
+ //
+
+ } else {
+
+ //
+ // Success!
+ //
+
+ break;
+ }
+
+ }
+
+ return(String);
+}
+
+
+/***************************************************************************\
+* FUNCTION: WritePrivateProfileInt
+*
+* PURPOSE: Writes out an integer to a profile file
+*
+* RETURNS: TRUE on success, FALSE on failure
+*
+* HISTORY:
+*
+* 12-Nov-92 Davidc Created.
+*
+\***************************************************************************/
+
+BOOL
+WritePrivateProfileInt(
+ LPCTSTR lpAppName,
+ LPCTSTR lpKeyName,
+ UINT Value,
+ LPCTSTR lpFileName
+ )
+{
+ NTSTATUS Status;
+ TCHAR String[30];
+ UNICODE_STRING UniString;
+
+ UniString.MaximumLength = 30;
+ UniString.Buffer = String;
+
+ Status = RtlIntegerToUnicodeString(Value,10,&UniString);
+
+ if (!NT_SUCCESS(Status)) {
+ return(FALSE);
+ }
+
+ return (WritePrivateProfileString(lpAppName, lpKeyName, UniString.Buffer, lpFileName));
+
+}
+
+
+/***************************************************************************\
+* FUNCTION: AllocAndExpandEnvironmentStrings
+*
+* PURPOSE: Allocates memory for and returns pointer to buffer containing
+* the passed string expanded to include environment strings
+* The returned buffer should be freed using Free()
+*
+* RETURNS: Pointer to expanded string or NULL on failure.
+*
+* HISTORY:
+*
+* 21-Dec-92 Davidc Created.
+*
+\***************************************************************************/
+
+LPTSTR
+AllocAndExpandEnvironmentStrings(
+ LPCTSTR lpszSrc
+ )
+{
+ LPTSTR String;
+ LONG LengthAllocated;
+ LONG LengthCopied;
+
+ //
+ // Pick a random buffer length, if it's not big enough reallocate
+ // it and try again until it is.
+ //
+
+ LengthAllocated = lstrlen(lpszSrc) + TYPICAL_STRING_LENGTH;
+
+ String = Alloc(LengthAllocated * sizeof(TCHAR));
+ if (String == NULL) {
+ DebugLog((DEB_ERROR, "AllocAndExpandEnvironmentStrings : Failed to allocate %d bytes for string\n", LengthAllocated * sizeof(TCHAR)));
+ return(NULL);
+ }
+
+ while (TRUE) {
+
+ LengthCopied = ExpandEnvironmentStrings( lpszSrc,
+ String,
+ LengthAllocated
+ );
+ if (LengthCopied == 0) {
+ DebugLog((DEB_ERROR, "AllocAndExpandEnvironmentStrings : ExpandEnvironmentStrings failed, error = %d\n", GetLastError()));
+ Free(String);
+ String = NULL;
+ break;
+ }
+
+ //
+ // If the buffer was too small, make it bigger and try again
+ //
+
+ if (LengthCopied > LengthAllocated) {
+
+ DebugLog((DEB_TRACE, "AllocAndExpandEnvironmentStrings: Failed with buffer length = %d, reallocating to %d and retrying (retry should succeed)\n", LengthAllocated, LengthCopied));
+
+ String = ReAlloc(String, LengthCopied * sizeof(TCHAR));
+ LengthAllocated = LengthCopied;
+ if (String == NULL) {
+ DebugLog((DEB_ERROR, "AllocAndExpandEnvironmentStrings : Failed to reallocate %d bytes for string", LengthAllocated * sizeof(TCHAR)));
+ break;
+ }
+
+ //
+ // Go back and try to expand the string again
+ //
+
+ } else {
+
+ //
+ // Success!
+ //
+
+ break;
+ }
+
+ }
+
+ return(String);
+}
+
+
+/***************************************************************************\
+* FUNCTION: AllocAndRegEnumKey
+*
+* PURPOSE: Allocates memory for and returns pointer to buffer containing
+* the next registry sub-key name under the specified key
+* The returned buffer should be freed using Free()
+*
+* RETURNS: Pointer to sub-key name or NULL on failure. The reason for the
+* error can be obtains using GetLastError()
+*
+* HISTORY:
+*
+* 21-Dec-92 Davidc Created.
+*
+\***************************************************************************/
+
+LPTSTR
+AllocAndRegEnumKey(
+ HKEY hKey,
+ DWORD iSubKey
+ )
+{
+ LPTSTR String;
+ LONG LengthAllocated;
+
+ //
+ // Pick a random buffer length, if it's not big enough reallocate
+ // it and try again until it is.
+ //
+
+ LengthAllocated = TYPICAL_STRING_LENGTH;
+
+ String = Alloc(LengthAllocated * sizeof(TCHAR));
+ if (String == NULL) {
+ DebugLog((DEB_ERROR, "AllocAndRegEnumKey : Failed to allocate %d bytes for string", LengthAllocated * sizeof(TCHAR)));
+ return(NULL);
+ }
+
+ while (TRUE) {
+
+ DWORD Error = RegEnumKey(hKey, iSubKey, String, LengthAllocated);
+ if (Error == ERROR_SUCCESS) {
+ break;
+ }
+
+ if (Error != ERROR_MORE_DATA) {
+
+ if (Error != ERROR_NO_MORE_ITEMS) {
+ DebugLog((DEB_ERROR, "AllocAndRegEnumKey : RegEnumKey failed, error = %d", Error));
+ }
+
+ Free(String);
+ String = NULL;
+ SetLastError(Error);
+ break;
+ }
+
+ //
+ // The buffer was too small, make it bigger and try again
+ //
+
+ DebugLog((DEB_TRACE, "AllocAndRegEnumKey: Failed with buffer length = %d, reallocating and retrying", LengthAllocated));
+
+ LengthAllocated *= 2;
+ String = ReAlloc(String, LengthAllocated * sizeof(TCHAR));
+ if (String == NULL) {
+ DebugLog((DEB_ERROR, "AllocAndRegEnumKey : Failed to reallocate %d bytes for string", LengthAllocated * sizeof(TCHAR)));
+ break;
+ }
+ }
+
+ return(String);
+}
+
+
+/***************************************************************************\
+* FUNCTION: AllocAndRegQueryValueEx
+*
+* PURPOSE: Version of RegQueryValueEx that returns value in allocated buffer.
+* The returned buffer should be freed using Free()
+*
+* RETURNS: Pointer to key value or NULL on failure. The reason for the
+* error can be obtains using GetLastError()
+*
+* HISTORY:
+*
+* 15-Jan-93 Davidc Created.
+*
+\***************************************************************************/
+
+LPTSTR
+AllocAndRegQueryValueEx(
+ HKEY hKey,
+ LPTSTR lpValueName,
+ LPDWORD lpReserved,
+ LPDWORD lpType
+ )
+{
+ LPTSTR String;
+ DWORD BytesAllocated;
+
+ //
+ // Pick a random buffer length, if it's not big enough reallocate
+ // it and try again until it is.
+ //
+
+ BytesAllocated = TYPICAL_STRING_LENGTH * sizeof(TCHAR);
+
+ String = Alloc(BytesAllocated);
+ if (String == NULL) {
+ DebugLog((DEB_ERROR, "AllocAndRegQueryValueEx : Failed to allocate %d bytes for string", BytesAllocated));
+ return(NULL);
+ }
+
+ while (TRUE) {
+
+ DWORD Error;
+ DWORD BytesReturned = BytesAllocated;
+
+ Error = RegQueryValueEx(hKey,
+ lpValueName,
+ lpReserved,
+ lpType,
+ (LPBYTE)String,
+ &BytesReturned);
+ if (Error == ERROR_SUCCESS) {
+ break;
+ }
+
+ if (Error != ERROR_MORE_DATA) {
+
+ DebugLog((DEB_ERROR, "AllocAndRegQueryValueEx : RegQueryValueEx failed, error = %d", Error));
+ Free(String);
+ String = NULL;
+ SetLastError(Error);
+ break;
+ }
+
+ //
+ // The buffer was too small, make it bigger and try again
+ //
+
+ DebugLog((DEB_TRACE, "AllocAndRegQueryValueEx: Failed with buffer length = %d bytes, reallocating and retrying", BytesAllocated));
+
+ BytesAllocated *= 2;
+ String = ReAlloc(String, BytesAllocated);
+ if (String == NULL) {
+ DebugLog((DEB_ERROR, "AllocAndRegQueryValueEx : Failed to reallocate %d bytes for string", BytesAllocated));
+ break;
+ }
+ }
+
+ return(String);
+}
+
+
+/***************************************************************************\
+* CentreWindow
+*
+* Purpose : Positions a window so that it is centred in its parent
+*
+* History:
+* 12-09-91 Davidc Created.
+\***************************************************************************/
+VOID
+CentreWindow(
+ HWND hwnd
+ )
+{
+ RECT rect;
+ LONG dx, dy;
+ LONG dxParent, dyParent;
+ LONG Style;
+
+ // Get window rect
+ GetWindowRect(hwnd, &rect);
+
+ dx = rect.right - rect.left;
+ dy = rect.bottom - rect.top;
+
+ // Get parent rect
+ Style = GetWindowLong(hwnd, GWL_STYLE);
+ if ((Style & WS_CHILD) == 0) {
+
+ // Return the desktop windows size (size of main screen)
+ dxParent = GetSystemMetrics(SM_CXSCREEN);
+ dyParent = GetSystemMetrics(SM_CYSCREEN);
+ } else {
+ HWND hwndParent;
+ RECT rectParent;
+
+ hwndParent = GetParent(hwnd);
+ if (hwndParent == NULL) {
+ hwndParent = GetDesktopWindow();
+ }
+
+ GetWindowRect(hwndParent, &rectParent);
+
+ dxParent = rectParent.right - rectParent.left;
+ dyParent = rectParent.bottom - rectParent.top;
+ }
+
+ // Centre the child in the parent
+ rect.left = (dxParent - dx) / 2;
+ rect.top = (dyParent - dy) / 3;
+
+ // Move the child into position
+ SetWindowPos(hwnd, HWND_TOPMOST, rect.left, rect.top, 0, 0, SWP_NOSIZE);
+
+ SetForegroundWindow(hwnd);
+}
+
+
+/***************************************************************************\
+* SetupSystemMenu
+*
+* Purpose : Does any manipulation required for a dialog system menu.
+* Should be called during WM_INITDIALOG processing for a dialog
+*
+* History:
+* 12-09-91 Davidc Created.
+\***************************************************************************/
+VOID
+SetupSystemMenu(
+ HWND hDlg
+ )
+{
+ // Remove the Close item from the system menu if we don't
+ // have a CANCEL button
+
+ if (GetDlgItem(hDlg, IDCANCEL) == NULL) {
+
+ HMENU hMenu = GetSystemMenu(hDlg, FALSE);
+
+ DeleteMenu(hMenu, SC_CLOSE, MF_BYCOMMAND);
+ }
+
+}
+
+/***************************************************************************\
+* FUNCTION: OpenIniFileUserMapping
+*
+* PURPOSE: Forces the ini file mapping apis to reference the current user's
+* registry.
+*
+* RETURNS: TRUE on success, FALSE on failure
+*
+* HISTORY:
+*
+* 24-Aug-92 Davidc Created.
+*
+\***************************************************************************/
+
+BOOL
+OpenIniFileUserMapping(
+ PGLOBALS pGlobals
+ )
+{
+ BOOL Result;
+ HANDLE ImpersonationHandle;
+
+ //
+ // Impersonate the user
+ //
+
+ if (pGlobals->IniRef == 0)
+ {
+
+ ImpersonationHandle = ImpersonateUser(&pGlobals->UserProcessData, NULL);
+
+ if (ImpersonationHandle == NULL) {
+ DebugLog((DEB_ERROR, "OpenIniFileUserMapping failed to impersonate user"));
+ return(FALSE);
+ }
+
+ DebugLog((DEB_TRACE, "Actually opening user mapping. User %s logged on\n",
+ pGlobals->UserLoggedOn ? "is" : "is not"));
+
+ Result = OpenProfileUserMapping();
+
+ if (!Result) {
+ DebugLog((DEB_ERROR, "OpenProfileUserMapping failed, error = %d", GetLastError()));
+ }
+
+ //
+ // Revert to being 'ourself'
+ //
+
+ if (!StopImpersonating(ImpersonationHandle)) {
+ DebugLog((DEB_ERROR, "OpenIniFileUserMapping failed to revert to self"));
+ }
+
+
+ }
+ else
+ {
+ Result = TRUE;
+ }
+
+ pGlobals->IniRef++;
+
+ DebugLog((DEB_TRACE, "ProfileUserMapping Refs = %d\n", pGlobals->IniRef));
+
+ return(Result);
+}
+
+/***************************************************************************\
+* FUNCTION: CloseIniFileUserMapping
+*
+* PURPOSE: Closes the ini file mapping to the user's registry such
+* that future use of the ini apis will fail if they reference
+* the user's registry.
+*
+* RETURNS: Nothing
+*
+* HISTORY:
+*
+* 24-Aug-92 Davidc Created.
+*
+\***************************************************************************/
+
+VOID
+CloseIniFileUserMapping(
+ PGLOBALS pGlobals
+ )
+{
+ BOOL Result;
+
+ if (pGlobals->IniRef)
+ {
+ if (--pGlobals->IniRef == 0)
+ {
+
+ DebugLog((DEB_TRACE, "Actually closing user mapping\n"));
+
+ Result = CloseProfileUserMapping();
+
+ if (!Result) {
+ DebugLog((DEB_ERROR, "CloseProfileUserMapping failed, error = %d", GetLastError()));
+ }
+
+ }
+
+ }
+
+ DebugLog((DEB_TRACE, "ProfileUserMapping Refs = %d\n", pGlobals->IniRef));
+}