Skip to content

Commit 52ee984

Browse files
committed
fix(starup): fixed the problem of being unable to run due to failure to downgrade rights at starup
1 parent afc27f7 commit 52ee984

File tree

1 file changed

+183
-23
lines changed

1 file changed

+183
-23
lines changed

src/main/main_initialization.c

Lines changed: 183 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -46,83 +46,243 @@ static BOOL IsElevated(void) {
4646
/* Attempt to relaunch self as standard user using Explorer's token */
4747
static BOOL RelaunchAsStandardUser(void) {
4848
HWND hShellWnd = GetShellWindow();
49-
if (!hShellWnd) return FALSE;
49+
if (!hShellWnd) {
50+
LOG_WARNING("GetShellWindow() returned NULL, Explorer may not be running.");
51+
return FALSE;
52+
}
5053

51-
DWORD dwShellPID;
54+
DWORD dwShellPID = 0;
5255
GetWindowThreadProcessId(hShellWnd, &dwShellPID);
56+
if (dwShellPID == 0) {
57+
LOG_WARNING("Failed to get Explorer PID.");
58+
return FALSE;
59+
}
5360

5461
HANDLE hShellProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, dwShellPID);
55-
if (!hShellProcess) return FALSE;
62+
if (!hShellProcess) {
63+
LOG_WARNING("Failed to open Explorer process, error: %lu", GetLastError());
64+
return FALSE;
65+
}
5666

5767
HANDLE hShellToken = NULL;
5868
if (!OpenProcessToken(hShellProcess, TOKEN_DUPLICATE, &hShellToken)) {
69+
LOG_WARNING("Failed to open Explorer token, error: %lu", GetLastError());
5970
CloseHandle(hShellProcess);
6071
return FALSE;
6172
}
6273

6374
HANDLE hNewToken = NULL;
6475
/* Duplicate the shell's token (which is medium integrity/standard user) */
6576
if (!DuplicateTokenEx(hShellToken, MAXIMUM_ALLOWED, NULL, SecurityImpersonation, TokenPrimary, &hNewToken)) {
77+
LOG_WARNING("Failed to duplicate token, error: %lu", GetLastError());
6678
CloseHandle(hShellToken);
6779
CloseHandle(hShellProcess);
6880
return FALSE;
6981
}
7082

7183
wchar_t szPath[MAX_PATH];
7284
GetModuleFileNameW(NULL, szPath, MAX_PATH);
73-
85+
7486
/* Reconstruct command line safely - CreateProcess might modify the buffer */
7587
wchar_t* pszOriginalCmdLine = GetCommandLineW();
7688
size_t cmdLen = wcslen(pszOriginalCmdLine) + 1;
7789
wchar_t* pszCmdLineCopy = (wchar_t*)malloc(cmdLen * sizeof(wchar_t));
78-
90+
7991
if (!pszCmdLineCopy) {
92+
LOG_WARNING("Failed to allocate command line buffer.");
8093
CloseHandle(hNewToken);
8194
CloseHandle(hShellToken);
8295
CloseHandle(hShellProcess);
8396
return FALSE;
8497
}
85-
98+
8699
wcscpy_s(pszCmdLineCopy, cmdLen, pszOriginalCmdLine);
87-
100+
88101
STARTUPINFOW si = {sizeof(STARTUPINFOW)};
89102
PROCESS_INFORMATION pi = {0};
90-
103+
91104
BOOL bResult = CreateProcessWithTokenW(hNewToken, LOGON_WITH_PROFILE, NULL, pszCmdLineCopy, 0, NULL, NULL, &si, &pi);
92105

93106
free(pszCmdLineCopy);
94107

95108
if (bResult) {
96-
LOG_INFO("Relaunched self as standard user (PID: %lu)", pi.dwProcessId);
109+
/* Verify the new process is actually running */
110+
DWORD exitCode = 0;
111+
if (WaitForSingleObject(pi.hProcess, 100) == WAIT_TIMEOUT) {
112+
/* Process is still running after 100ms - success */
113+
LOG_INFO("Relaunched self as standard user (PID: %lu)", pi.dwProcessId);
114+
} else if (GetExitCodeProcess(pi.hProcess, &exitCode) && exitCode != STILL_ACTIVE) {
115+
/* Process exited immediately - something went wrong */
116+
LOG_WARNING("New process exited immediately with code: %lu", exitCode);
117+
bResult = FALSE;
118+
}
97119
CloseHandle(pi.hProcess);
98120
CloseHandle(pi.hThread);
99121
} else {
100-
LOG_ERROR("Failed to relaunch as standard user, error: %lu", GetLastError());
122+
LOG_WARNING("CreateProcessWithTokenW failed, error: %lu", GetLastError());
101123
}
102124

103125
CloseHandle(hNewToken);
104126
CloseHandle(hShellToken);
105127
CloseHandle(hShellProcess);
106-
128+
107129
return bResult;
108130
}
109131

110-
/* Drop Administrator privileges if present to ensure Drag & Drop works from Explorer */
111-
static void DropPrivileges(void) {
112-
if (IsElevated()) {
113-
LOG_INFO("Elevated privileges detected. Attempting to switch to standard user...");
114-
115-
/* Prevent infinite loop if relaunch fails or we are genuinely the admin user (e.g. built-in Admin) */
116-
/* But here we just try once. If it succeeds, we exit. */
117-
118-
if (RelaunchAsStandardUser()) {
119-
/* Exit this elevated instance */
120-
ExitProcess(0);
132+
/* Check if UAC is enabled - returns FALSE if disabled or uncertain */
133+
static BOOL IsUACEnabled(void) {
134+
HKEY hKey;
135+
DWORD dwValue = 0; /* Default to DISABLED for safety - skip privilege drop if uncertain */
136+
DWORD dwSize = sizeof(DWORD);
137+
138+
LSTATUS status = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
139+
L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\System",
140+
0, KEY_READ, &hKey);
141+
142+
if (status != ERROR_SUCCESS) {
143+
LOG_WARNING("Cannot read UAC registry key (error: %ld), assuming UAC disabled for safety", status);
144+
return FALSE;
145+
}
146+
147+
status = RegQueryValueExW(hKey, L"EnableLUA", NULL, NULL, (LPBYTE)&dwValue, &dwSize);
148+
RegCloseKey(hKey);
149+
150+
if (status != ERROR_SUCCESS) {
151+
LOG_WARNING("Cannot read EnableLUA value (error: %ld), assuming UAC disabled for safety", status);
152+
return FALSE;
153+
}
154+
155+
LOG_INFO("UAC EnableLUA registry value: %lu", dwValue);
156+
return dwValue != 0;
157+
}
158+
159+
/* Check if Secondary Logon service is running - required for CreateProcessWithTokenW */
160+
static BOOL IsSecondaryLogonServiceRunning(void) {
161+
SC_HANDLE hSCManager = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
162+
if (!hSCManager) {
163+
LOG_WARNING("Cannot open SCManager (error: %lu), assuming service unavailable", GetLastError());
164+
return FALSE;
165+
}
166+
167+
SC_HANDLE hService = OpenServiceW(hSCManager, L"seclogon", SERVICE_QUERY_STATUS);
168+
if (!hService) {
169+
DWORD err = GetLastError();
170+
CloseServiceHandle(hSCManager);
171+
if (err == ERROR_SERVICE_DOES_NOT_EXIST) {
172+
LOG_WARNING("Secondary Logon service does not exist on this system");
121173
} else {
122-
LOG_WARNING("Failed to switch to standard user. Drag & Drop may be restricted.");
174+
LOG_WARNING("Cannot open Secondary Logon service (error: %lu)", err);
123175
}
176+
return FALSE;
177+
}
178+
179+
SERVICE_STATUS status;
180+
BOOL bRunning = FALSE;
181+
if (QueryServiceStatus(hService, &status)) {
182+
bRunning = (status.dwCurrentState == SERVICE_RUNNING);
183+
LOG_INFO("Secondary Logon service state: %lu (running=%s)",
184+
status.dwCurrentState, bRunning ? "yes" : "no");
124185
} else {
186+
LOG_WARNING("Cannot query Secondary Logon service status (error: %lu)", GetLastError());
187+
}
188+
189+
CloseServiceHandle(hService);
190+
CloseServiceHandle(hSCManager);
191+
return bRunning;
192+
}
193+
194+
/* Check if running on Windows Server edition */
195+
static BOOL IsWindowsServer(void) {
196+
OSVERSIONINFOEXW osvi = {sizeof(OSVERSIONINFOEXW)};
197+
DWORDLONG dwlConditionMask = 0;
198+
199+
VER_SET_CONDITION(dwlConditionMask, VER_PRODUCT_TYPE, VER_EQUAL);
200+
osvi.wProductType = VER_NT_WORKSTATION;
201+
202+
/* If this is NOT a workstation, it's a server */
203+
BOOL bIsWorkstation = VerifyVersionInfoW(&osvi, VER_PRODUCT_TYPE, dwlConditionMask);
204+
205+
if (!bIsWorkstation) {
206+
LOG_INFO("Detected Windows Server edition");
207+
return TRUE;
208+
}
209+
return FALSE;
210+
}
211+
212+
/* Check if Explorer (shell) is running as elevated */
213+
static BOOL IsShellElevated(void) {
214+
HWND hShellWnd = GetShellWindow();
215+
if (!hShellWnd) return TRUE; /* Assume elevated if no shell */
216+
217+
DWORD dwShellPID = 0;
218+
GetWindowThreadProcessId(hShellWnd, &dwShellPID);
219+
if (dwShellPID == 0) return TRUE;
220+
221+
HANDLE hShellProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, dwShellPID);
222+
if (!hShellProcess) return TRUE;
223+
224+
HANDLE hShellToken = NULL;
225+
BOOL bShellElevated = TRUE; /* Default to TRUE (skip privilege drop) */
226+
227+
if (OpenProcessToken(hShellProcess, TOKEN_QUERY, &hShellToken)) {
228+
TOKEN_ELEVATION elevation;
229+
DWORD cbSize = sizeof(TOKEN_ELEVATION);
230+
if (GetTokenInformation(hShellToken, TokenElevation, &elevation, sizeof(elevation), &cbSize)) {
231+
bShellElevated = elevation.TokenIsElevated;
232+
}
233+
CloseHandle(hShellToken);
234+
}
235+
236+
CloseHandle(hShellProcess);
237+
return bShellElevated;
238+
}
239+
240+
/* Drop Administrator privileges if present to ensure Drag & Drop works from Explorer */
241+
static void DropPrivileges(void) {
242+
/* CRITICAL: This function must NEVER prevent the application from running.
243+
* All checks are designed to fail-safe (skip privilege drop on any uncertainty).
244+
*/
245+
246+
if (!IsElevated()) {
125247
LOG_INFO("Running as standard user (optimal for Drag & Drop).");
248+
return;
249+
}
250+
251+
LOG_INFO("Elevated privileges detected. Checking if privilege drop is safe...");
252+
253+
/* Check 1: Windows Server - often has different security policies */
254+
if (IsWindowsServer()) {
255+
LOG_INFO("Running on Windows Server, skipping privilege drop for compatibility.");
256+
return;
257+
}
258+
259+
/* Check 2: UAC disabled - privilege drop is meaningless and may cause issues */
260+
if (!IsUACEnabled()) {
261+
LOG_INFO("UAC is disabled, skipping privilege drop (Drag & Drop may be restricted).");
262+
return;
263+
}
264+
265+
/* Check 3: Secondary Logon service - required for CreateProcessWithTokenW */
266+
if (!IsSecondaryLogonServiceRunning()) {
267+
LOG_INFO("Secondary Logon service not running, skipping privilege drop.");
268+
return;
269+
}
270+
271+
/* Check 4: Explorer itself is elevated - privilege drop would be pointless */
272+
if (IsShellElevated()) {
273+
LOG_INFO("Explorer is also elevated, skipping privilege drop.");
274+
return;
275+
}
276+
277+
LOG_INFO("All preconditions met. Attempting to switch to standard user...");
278+
279+
if (RelaunchAsStandardUser()) {
280+
LOG_INFO("Relaunch successful, exiting elevated instance.");
281+
/* Exit this elevated instance */
282+
ExitProcess(0);
283+
} else {
284+
LOG_WARNING("Failed to switch to standard user. Continuing with elevated privileges.");
285+
LOG_WARNING("Drag & Drop from Explorer may be restricted.");
126286
}
127287
}
128288

0 commit comments

Comments
 (0)