blob: 21531de8c4682c0dda7e8179a7bfeaba2f0c2c3b [file] [log] [blame]
Constantin Kaplinsky729598c2006-05-25 05:12:25 +00001/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
2 *
3 * This is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This software is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this software; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
16 * USA.
17 */
18
19// -=- Currentuser.cxx
20
21#include <stdlib.h>
22#include <rfb/LogWriter.h>
23#include <rfb_win32/CurrentUser.h>
24#include <rfb_win32/DynamicFn.h>
25#include <rfb_win32/Service.h>
26#include <rfb_win32/OSVersion.h>
27#include <lmcons.h>
28
29using namespace rfb;
30using namespace win32;
31
32static LogWriter vlog("CurrentUser");
33
34
35const TCHAR* shellIconClass = _T("Shell_TrayWnd");
36
37BOOL CALLBACK enumWindows(HWND hwnd, LPARAM lParam) {
38 TCHAR className[16];
39 if (GetClassName(hwnd, className, sizeof(className)) &&
40 (_tcscmp(className, shellIconClass) == 0)) {
41 vlog.debug("located tray icon window (%s)", (const char*)CStr(className));
42 DWORD processId = 0;
43 GetWindowThreadProcessId(hwnd, &processId);
44 if (!processId)
45 return TRUE;
46 Handle process = OpenProcess(MAXIMUM_ALLOWED, FALSE, processId);
47 if (!process.h)
48 return TRUE;
49 if (!OpenProcessToken(process, MAXIMUM_ALLOWED, (HANDLE*)lParam))
50 return TRUE;
51 vlog.debug("obtained user token");
52 return FALSE;
53 }
54 return TRUE;
55}
56
57BOOL CALLBACK enumDesktops(LPTSTR lpszDesktop, LPARAM lParam) {
58 HDESK desktop = OpenDesktop(lpszDesktop, 0, FALSE, DESKTOP_ENUMERATE);
59 vlog.debug("opening \"%s\"", lpszDesktop);
60 if (!desktop) {
61 vlog.info("desktop \"%s\" inaccessible", (const char*)CStr(lpszDesktop));
62 return TRUE;
63 }
64 BOOL result = EnumDesktopWindows(desktop, enumWindows, lParam);
65 if (!CloseDesktop(desktop))
66 vlog.info("unable to close desktop: %ld", GetLastError());
67 return result;
68}
69
70
71CurrentUserToken::CurrentUserToken() : isSafe_(false) {
72 if (isServiceProcess()) {
73 // If the platform is Windows 95/98/Me then we must fake the token's presence
74 if (osVersion.isPlatformWindows) {
75 try {
76 UserName un;
77 h = INVALID_HANDLE_VALUE;
78 } catch (rdr::SystemException& e) {
79 if (e.err != ERROR_NOT_LOGGED_ON)
80 throw;
81 if (FindWindow(shellIconClass, 0))
82 h = INVALID_HANDLE_VALUE;
83 }
84 isSafe_ = (h != 0);
85 return;
86 }
87
88 // Try to get the user token using the Terminal Services APIs
89 // NB: This will only work under XP/2003 and later
90 typedef BOOL (WINAPI *WTSQueryUserToken_proto)(ULONG, PHANDLE);
91 DynamicFn<WTSQueryUserToken_proto> _WTSQueryUserToken(_T("wtsapi32.dll"), "WTSQueryUserToken");
92 if (_WTSQueryUserToken.isValid()) {
93 (*_WTSQueryUserToken)(-1, &h);
94 isSafe_ = true;
95 return;
96 }
97
98 // Try to find the Shell Tray Icon window and take its token
99 // NB: This will only work under NT/2K (and later, but they're dealt with above)
100 // NB: If the shell is not running then this will return an Unsafe Null token.
DRCc75dc442010-05-20 07:44:49 +0000101 EnumDesktops(GetProcessWindowStation(), enumDesktops, (LPARAM)&h);
Constantin Kaplinsky729598c2006-05-25 05:12:25 +0000102 isSafe_ = (h != 0);
103 } else {
104 // Try to open the security token for the User-Mode process
105 if (!OpenProcessToken(GetCurrentProcess(), GENERIC_ALL, &h)) {
106 DWORD err = GetLastError();
107 if (err != ERROR_CALL_NOT_IMPLEMENTED)
108 throw rdr::SystemException("OpenProcessToken failed", err);
109 // Under Windows 95/98/Me, we fake the handle value...
110 h = INVALID_HANDLE_VALUE;
111 }
112 isSafe_ = true;
113 }
114}
115
116
117ImpersonateCurrentUser::ImpersonateCurrentUser() {
118 RegCloseKey(HKEY_CURRENT_USER);
119 if (!isServiceProcess())
120 return;
121 if (!token.canImpersonate())
122 throw rdr::Exception("Cannot impersonate unsafe or null token");
123 if (!ImpersonateLoggedOnUser(token)) {
124 DWORD err = GetLastError();
125 if (err != ERROR_CALL_NOT_IMPLEMENTED)
126 throw rdr::SystemException("Failed to impersonate user", GetLastError());
127 }
128}
129
130ImpersonateCurrentUser::~ImpersonateCurrentUser() {
131 if (!RevertToSelf()) {
132 DWORD err = GetLastError();
133 if (err != ERROR_CALL_NOT_IMPLEMENTED)
134 exit(err);
135 }
136 RegCloseKey(HKEY_CURRENT_USER);
137}
138
139
140UserName::UserName() : TCharArray(UNLEN+1) {
141 DWORD len = UNLEN+1;
142 if (!GetUserName(buf, &len))
143 throw rdr::SystemException("GetUserName failed", GetLastError());
144}
145
146
147UserSID::UserSID() {
148 CurrentUserToken token;
149 if (!token.canImpersonate())
150 return;
151 setSID(Sid::FromToken(token.h));
152}