1 
2 #include "stdafx.h"
3 #include "boinccas.h"
4 #include "launcher.h"
5 
6 
7 #ifndef SECURITY_MANDATORY_UNTRUSTED_RID
8 
9 #define SECURITY_MANDATORY_UNTRUSTED_RID            (0x00000000L)
10 #define SECURITY_MANDATORY_LOW_RID                  (0x00001000L)
11 #define SECURITY_MANDATORY_MEDIUM_RID               (0x00002000L)
12 #define SECURITY_MANDATORY_HIGH_RID                 (0x00003000L)
13 #define SECURITY_MANDATORY_SYSTEM_RID               (0x00004000L)
14 #define SECURITY_MANDATORY_PROTECTED_PROCESS_RID    (0x00005000L)
15 
16 typedef struct _TOKEN_MANDATORY_LABEL {
17     SID_AND_ATTRIBUTES Label;
18 } TOKEN_MANDATORY_LABEL, *PTOKEN_MANDATORY_LABEL;
19 
20 typedef enum _MANDATORY_LEVEL {
21     MandatoryLevelUntrusted = 0,
22     MandatoryLevelLow,
23     MandatoryLevelMedium,
24     MandatoryLevelHigh,
25     MandatoryLevelSystem,
26     MandatoryLevelSecureProcess,
27     MandatoryLevelCount
28 } MANDATORY_LEVEL, *PMANDATORY_LEVEL;
29 
30 #define TokenVirtualizationEnabled ((TOKEN_INFORMATION_CLASS)24)
31 #define TokenIntegrityLevel ((TOKEN_INFORMATION_CLASS)25)
32 
33 #endif //!SECURITY_MANDATORY_UNTRUSTED_RID
34 
35 /*!
36 @brief Function enables/disables/removes a privelege associated with the given token
37 @detailed Calls LookupPrivilegeValue() and AdjustTokenPrivileges()
38 @param[in] hToken - access token handle
39 @param[in] lpszPrivilege - name of privilege to enable/disable
40 @param[in] dwAttributes - (SE_PRIVILEGE_ENABLED) to enable or (0) disable or (SE_PRIVILEGE_REMOVED) to remove privilege
41 @return HRESULT code
42 @todo Removing was checked. To check enabling and disabling.
43 */
SetPrivilege(HANDLE hToken,LPCTSTR lpszPrivilege,DWORD dwAttributes=SE_PRIVILEGE_ENABLED)44 inline HRESULT SetPrivilege(
45 		  HANDLE hToken,
46 		  LPCTSTR lpszPrivilege,
47 		  DWORD dwAttributes=SE_PRIVILEGE_ENABLED
48 		  )
49 {
50 	HRESULT hr=S_OK;
51 	LUID luid;
52 
53 	if ( LookupPrivilegeValue(
54 			NULL,            // lookup privilege on local system
55 			lpszPrivilege,   // privilege to lookup
56 			&luid ) )        // receives LUID of privilege
57 	{
58 		TOKEN_PRIVILEGES tp;
59 		tp.PrivilegeCount = 1;
60 		tp.Privileges[0].Luid = luid;
61 		tp.Privileges[0].Attributes = dwAttributes;
62 
63 		// Enable the privilege or disable all privileges.
64 
65 		if ( !AdjustTokenPrivileges(
66 				hToken,
67 				FALSE,
68 				&tp,
69 				sizeof(TOKEN_PRIVILEGES),
70 				(PTOKEN_PRIVILEGES) NULL,
71 				(PDWORD) NULL) )
72 			hr=HRESULT_FROM_WIN32(GetLastError());
73 	}//if(LookupPrivilegeValue(...))
74 	else
75 		hr=HRESULT_FROM_WIN32(GetLastError());
76 
77 	return hr;
78 }
79 
80 /*!
81 Function removes the priveleges which are not associated by default with explorer.exe at Medium Integration Level in Vista
82 @returns HRESULT of the operation on SE_CREATE_GLOBAL_NAME (="SeCreateGlobalPrivilege")
83 */
ReducePrivilegesForMediumIL(HANDLE hToken)84 inline HRESULT ReducePrivilegesForMediumIL(HANDLE hToken)
85 {
86 	HRESULT hr=S_OK;
87 	hr=SetPrivilege(hToken, SE_CREATE_GLOBAL_NAME, SE_PRIVILEGE_REMOVED);
88 
89 	SetPrivilege(hToken, SE_BACKUP_NAME, SE_PRIVILEGE_REMOVED);
90 	SetPrivilege(hToken, SE_CREATE_PAGEFILE_NAME, SE_PRIVILEGE_REMOVED);
91 	SetPrivilege(hToken, TEXT("SeCreateSymbolicLinkPrivilege"), SE_PRIVILEGE_REMOVED);
92 	SetPrivilege(hToken, SE_DEBUG_NAME, SE_PRIVILEGE_REMOVED);
93 	SetPrivilege(hToken, SE_IMPERSONATE_NAME, SE_PRIVILEGE_REMOVED);
94 	SetPrivilege(hToken, SE_INC_BASE_PRIORITY_NAME, SE_PRIVILEGE_REMOVED);
95 	SetPrivilege(hToken, SE_INCREASE_QUOTA_NAME, SE_PRIVILEGE_REMOVED);
96 	SetPrivilege(hToken, SE_LOAD_DRIVER_NAME, SE_PRIVILEGE_REMOVED);
97 	SetPrivilege(hToken, SE_MANAGE_VOLUME_NAME, SE_PRIVILEGE_REMOVED);
98 	SetPrivilege(hToken, SE_PROF_SINGLE_PROCESS_NAME, SE_PRIVILEGE_REMOVED);
99 	SetPrivilege(hToken, SE_REMOTE_SHUTDOWN_NAME, SE_PRIVILEGE_REMOVED);
100 	SetPrivilege(hToken, SE_RESTORE_NAME, SE_PRIVILEGE_REMOVED);
101 	SetPrivilege(hToken, SE_SECURITY_NAME, SE_PRIVILEGE_REMOVED);
102 	SetPrivilege(hToken, SE_SYSTEM_ENVIRONMENT_NAME, SE_PRIVILEGE_REMOVED);
103 	SetPrivilege(hToken, SE_SYSTEM_PROFILE_NAME, SE_PRIVILEGE_REMOVED);
104 	SetPrivilege(hToken, SE_SYSTEMTIME_NAME, SE_PRIVILEGE_REMOVED);
105 	SetPrivilege(hToken, SE_TAKE_OWNERSHIP_NAME, SE_PRIVILEGE_REMOVED);
106 
107 	return hr;
108 }
109 
110 /*!
111 @brief Gets Integration level of the given process in Vista.
112 In the older OS assumes the integration level is equal to SECURITY_MANDATORY_HIGH_RID
113 
114 The function opens the process for all access and opens its token for all access.
115 Then it extracts token information and closes the handles.
116 @param[in] dwProcessId ID of the process to operate
117 @param[out] pdwProcessIL pointer to write the value
118 @return HRESULT
119 @retval <return value> { description }
120 @remarks Function check for OS version by querying the presence of Kernel32.GetProductInfo function.
121 This way is used due to the function is called from InstallShield12 script, so GetVersionEx returns incorrect value.
122 @todo restrict access rights when quering for tokens
123 */
GetProcessIL(DWORD dwProcessId,LPDWORD pdwProcessIL)124 inline HRESULT GetProcessIL(DWORD dwProcessId, LPDWORD pdwProcessIL)
125 {
126 	HRESULT hr=S_OK;
127 	if(!pdwProcessIL)
128 		hr=E_INVALIDARG;
129 	if(SUCCEEDED(hr))
130 	{
131 		bool bVista=false;
132 		{
133 			// When the function is called from IS12, GetVersionEx returns dwMajorVersion=5 on Vista!
134 			HMODULE hmodKernel32=LoadLibrary(L"Kernel32");
135 			if(hmodKernel32 && GetProcAddress(hmodKernel32, "GetProductInfo"))
136 				bVista=true;
137 			if(hmodKernel32) FreeLibrary(hmodKernel32);
138 		}
139 
140 		DWORD dwIL=SECURITY_MANDATORY_HIGH_RID;
141 		if(bVista)
142 		{//Vista
143 			HANDLE hToken=NULL;
144 			HANDLE hProcess=OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId);
145 			if(hProcess)
146 			{
147 				if(OpenProcessToken(hProcess, TOKEN_ALL_ACCESS, &hToken))
148 				{
149 					PTOKEN_MANDATORY_LABEL pTIL=NULL;
150 					DWORD dwSize=0;
151 					if (!GetTokenInformation(hToken, TokenIntegrityLevel, NULL, 0, &dwSize)
152 						&& ERROR_INSUFFICIENT_BUFFER==GetLastError() && dwSize)
153 						pTIL=(PTOKEN_MANDATORY_LABEL)HeapAlloc(GetProcessHeap(), 0, dwSize);
154 
155 					if(pTIL && GetTokenInformation(hToken, TokenIntegrityLevel, pTIL, dwSize, &dwSize))
156 					{
157 						LPBYTE lpb=GetSidSubAuthorityCount(pTIL->Label.Sid);
158 						if(lpb)
159 							dwIL = *GetSidSubAuthority(pTIL->Label.Sid, *lpb-1);
160 						else
161 							hr=E_UNEXPECTED;
162 					}
163 					if(pTIL)
164 						HeapFree(GetProcessHeap(), 0, pTIL);
165 					CloseHandle(hToken);
166 				}//if(OpenProcessToken(...))
167 				CloseHandle(hProcess);
168 			}//if(hProcess)
169 		}//if(bVista)
170 		if(SUCCEEDED(hr))
171 			*pdwProcessIL=dwIL;
172 	}//if(SUCCEEDED(hr))
173 	return hr;
174 }
175 
176 /*!
177 @brief Function launches process with the integration level of Explorer on Vista. On the previous OS, simply creates the process.
178 
179 Function gets the integration level of the current process and Explorer, then launches the new process.
180 If the integration levels are equal, CreateProcess is called.
181 If Explorer has Medium IL, and the current process has High IL, new token is created, its rights are adjusted
182 and CreateProcessWithTokenW is called.
183 If Explorer has Medium IL, and the current process has High IL, error is returned.
184 @param[in] szProcessName - the name of exe file (see CreatePorcess())
185 @param[in] szCmdLine - the name of exe file (see CreatePorcess())
186 @return HRESULT code
187 @note The function cannot be used in services, due to if uses USER32.FindWindow() to get the proper instance of Explorer.
188 The parent of new process in taskmgr.exe, but not the current process.
189 @sa ReducePrivilegesForMediumIL()
190 */
CreateProcessWithExplorerIL(LPWSTR szProcessName,LPWSTR szCmdLine)191 HRESULT CreateProcessWithExplorerIL(LPWSTR szProcessName, LPWSTR szCmdLine)
192 {
193     HRESULT hr = S_OK;
194     BOOL bRet;
195     PROCESS_INFORMATION ProcInfo = {0};
196     STARTUPINFO StartupInfo = {0};
197     bool bVista = false;
198 
199 	// When the function is called from IS12, GetVersionEx returns dwMajorVersion=5 on Vista!
200 	HMODULE hmodKernel32 = LoadLibrary(_T("Kernel32"));
201     if (hmodKernel32) {
202         if (GetProcAddress(hmodKernel32, "GetProductInfo")) {
203             bVista = true;
204         }
205         FreeLibrary(hmodKernel32);
206     }
207 
208 	if(bVista)
209 	{
210 	    HANDLE hToken;
211 	    HANDLE hNewToken;
212 		DWORD dwCurIL = SECURITY_MANDATORY_HIGH_RID, dwExplorerIL = SECURITY_MANDATORY_HIGH_RID;
213 		DWORD dwExplorerID = 0;
214         DWORD dwEnableVirtualization = 0;
215 
216 		HWND hwndShell = ::FindWindow( _T("Progman"), NULL);
217 		if(hwndShell) GetWindowThreadProcessId(hwndShell, &dwExplorerID);
218 
219 		GetProcessIL(dwExplorerID, &dwExplorerIL);
220 		GetProcessIL(GetCurrentProcessId(), &dwCurIL);
221 
222         if( (dwCurIL == SECURITY_MANDATORY_HIGH_RID) && (dwExplorerIL == SECURITY_MANDATORY_MEDIUM_RID) )
223 		{
224 			HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwExplorerID);
225 			if(hProcess)
226 			{
227 				if(OpenProcessToken(hProcess, TOKEN_ALL_ACCESS, &hToken))
228 				{
229                     if(!DuplicateTokenEx(hToken, TOKEN_ALL_ACCESS, NULL, SecurityImpersonation, TokenPrimary, &hNewToken)) {
230 						hr = HRESULT_FROM_WIN32(GetLastError());
231                     }
232 
233 					if(SUCCEEDED(hr)) {
234 
235 						hr = ReducePrivilegesForMediumIL(hNewToken);
236 
237                         SetTokenInformation(
238                             hNewToken,
239                             TokenVirtualizationEnabled,
240                             &dwEnableVirtualization,
241                             sizeof(DWORD)
242                         );
243 
244                         if(SUCCEEDED(hr)) {
245 							bRet = CreateProcessAsUser(
246                                 hNewToken,
247                                 szProcessName,
248                                 szCmdLine,
249                                 NULL,
250                                 NULL,
251                                 FALSE,
252                                 NORMAL_PRIORITY_CLASS,
253                                 NULL,
254                                 NULL,
255                                 &StartupInfo,
256                                 &ProcInfo
257                             );
258                             if(!bRet) {
259 								hr = HRESULT_FROM_WIN32(GetLastError());
260                             }
261 						}
262                         CloseHandle(hNewToken);
263                     } else {
264 						hr = HRESULT_FROM_WIN32(GetLastError());
265                     }
266 					CloseHandle(hToken);
267                 } else {
268 					hr = HRESULT_FROM_WIN32(GetLastError());
269                 }
270 				CloseHandle(hProcess);
271 			}
272 		} else if ((dwCurIL == SECURITY_MANDATORY_MEDIUM_RID) && (dwExplorerIL == SECURITY_MANDATORY_HIGH_RID)) {
273 			hr = E_ACCESSDENIED;
274 		}
275 	}
276 
277 	if(!ProcInfo.dwProcessId) {
278 		bRet = CreateProcess(
279             szProcessName,
280             szCmdLine,
281 			NULL,
282             NULL,
283             FALSE,
284             0,
285             NULL,
286             NULL,
287             &StartupInfo,
288             &ProcInfo
289         );
290         if(!bRet) {
291 			hr = HRESULT_FROM_WIN32(GetLastError());
292         }
293 	}
294 
295 	return hr;
296 }
297 
298 
299