10#ifndef ONLY_SERVICE_LAUNCHING
35 LPCWSTR siblingFilePath,
38 if (wcslen(siblingFilePath) >= MAX_PATH)
43 wcsncpy(destinationBuffer, siblingFilePath, MAX_PATH);
44 if (!PathRemoveFileSpecW(destinationBuffer))
49 if (wcslen(destinationBuffer) + wcslen(newFileName) >= MAX_PATH)
73 const WCHAR *updateInfoDir,
77 WCHAR workingDirectory[
MAX_PATH + 1] = { L
'\0' };
78 wcsncpy(workingDirectory, installationDir, MAX_PATH);
82 WCHAR inifile[
MAX_PATH + 1] = { L
'\0' };
83 wcsncpy(inifile, installationDir, MAX_PATH);
93 if (!GetPrivateProfileStringW(L
"PostUpdateWin", L
"ExeRelPath",
nullptr,
94 exefile, MAX_PATH + 1, inifile))
99 if (!GetPrivateProfileStringW(L
"PostUpdateWin", L
"ExeArg",
nullptr, exearg,
100 MAX_PATH + 1, inifile))
105 if (!GetPrivateProfileStringW(L
"PostUpdateWin", L
"ExeAsync", L
"TRUE",
107 sizeof(exeasync)/
sizeof(exeasync[0]),
113 WCHAR exefullpath[
MAX_PATH + 1] = { L
'\0' };
114 wcsncpy(exefullpath, installationDir, MAX_PATH);
126 WCHAR slogFile[
MAX_PATH + 1] = { L
'\0' };
127 wcsncpy(slogFile, updateInfoDir, MAX_PATH);
133 WCHAR dummyArg[14] = { L
'\0' };
134 wcsncpy(dummyArg, L
"argv0ignored ",
sizeof(dummyArg) /
sizeof(dummyArg[0]) - 1);
136 size_t len = wcslen(exearg) + wcslen(dummyArg);
137 WCHAR *cmdline = (WCHAR *) malloc((len + 1) *
sizeof(WCHAR));
143 wcsncpy(cmdline, dummyArg, len);
144 wcscat(cmdline, exearg);
147 !_wcsnicmp(exeasync, L
"false", 6) ||
148 !_wcsnicmp(exeasync, L
"0", 2))
156 CopyFileW(slogFile, dlogFile,
false);
158 STARTUPINFOW si = {
sizeof(si), 0};
160 PROCESS_INFORMATION pi = {0};
165 ok = CreateProcessAsUserW(userToken,
179 ok = CreateProcessW(exefullpath,
194 WaitForSingleObject(pi.hProcess, INFINITE);
195 CloseHandle(pi.hProcess);
196 CloseHandle(pi.hThread);
213 SC_HANDLE
manager = OpenSCManager(
nullptr,
nullptr,
214 SC_MANAGER_ALL_ACCESS);
221 SC_HANDLE svc = OpenServiceW(manager,
SVC_NAME,
225 CloseServiceHandle(manager);
232 CloseServiceHandle(manager);
236 if (!QueryServiceConfigW(svc,
nullptr, 0, &bytesNeeded) &&
237 GetLastError() != ERROR_INSUFFICIENT_BUFFER)
239 CloseServiceHandle(svc);
245 std::unique_ptr<char[]> serviceConfigBuffer = std::make_unique<char[]>(bytesNeeded);
246 if (!QueryServiceConfigW(svc,
247 reinterpret_cast<QUERY_SERVICE_CONFIGW*
>(serviceConfigBuffer.get()),
248 bytesNeeded, &bytesNeeded))
250 CloseServiceHandle(svc);
254 CloseServiceHandle(svc);
256 QUERY_SERVICE_CONFIGW &serviceConfig =
257 *
reinterpret_cast<QUERY_SERVICE_CONFIGW*
>(serviceConfigBuffer.get());
259 PathUnquoteSpacesW(serviceConfig.lpBinaryPathName);
262 WCHAR tmpService[
MAX_PATH + 1] = { L
'\0' };
264 L
"maintenanceservice_tmp.exe"))
270 WCHAR newMaintServicePath[
MAX_PATH + 1] = { L
'\0' };
271 wcsncpy(newMaintServicePath, installDir, MAX_PATH);
273 L
"maintenanceservice.exe");
277 if (!CopyFileW(newMaintServicePath, tmpService, FALSE))
283 STARTUPINFOW si = {0};
284 si.cb =
sizeof(STARTUPINFOW);
287 PROCESS_INFORMATION pi = {0};
288 WCHAR cmdLine[64] = {
'\0' };
289 wcsncpy(cmdLine, L
"dummyparam.exe upgrade",
290 sizeof(cmdLine) /
sizeof(cmdLine[0]) - 1);
291 BOOL svcUpdateProcessStarted = CreateProcessW(tmpService,
293 nullptr,
nullptr, FALSE,
295 nullptr, installDir, &si, &pi);
296 if (svcUpdateProcessStarted)
298 CloseHandle(pi.hProcess);
299 CloseHandle(pi.hThread);
301 return svcUpdateProcessStarted;
322 if (lastState != SERVICE_STOPPED)
324 return 20000 + lastState;
328 SC_HANDLE serviceManager = OpenSCManager(
nullptr,
nullptr,
330 SC_MANAGER_ENUMERATE_SERVICE);
337 SC_HANDLE service = OpenServiceW(serviceManager,
342 CloseServiceHandle(serviceManager);
348 const DWORD maxWaitMS = 5000;
349 DWORD currentWaitMS = 0;
350 DWORD lastError = ERROR_SUCCESS;
351 while (currentWaitMS < maxWaitMS)
353 BOOL result = StartServiceW(service, argc, argv);
356 lastError = ERROR_SUCCESS;
361 lastError = GetLastError();
364 currentWaitMS += 100;
366 CloseServiceHandle(service);
367 CloseServiceHandle(serviceManager);
371#ifndef ONLY_SERVICE_LAUNCHING
389 LPCWSTR *updaterServiceArgv =
new LPCWSTR[argc + 2];
390 updaterServiceArgv[0] = L
"MozillaMaintenance";
391 updaterServiceArgv[1] = L
"software-update";
393 for (
int i = 0;
i < argc; ++
i)
395 updaterServiceArgv[
i + 2] = argv[
i];
401 delete[] updaterServiceArgv;
415 if (wcslen(base) + wcslen(extra) >= MAX_PATH)
420 return PathAppendW(base, extra);
433 WCHAR updateStatusFilePath[
MAX_PATH + 1] = { L
'\0' };
434 wcsncpy(updateStatusFilePath, updateDirPath, MAX_PATH);
440 const char pending[] =
"pending";
441 HANDLE statusFile = CreateFileW(updateStatusFilePath, GENERIC_WRITE, 0,
442 nullptr, CREATE_ALWAYS, 0,
nullptr);
443 if (statusFile == INVALID_HANDLE_VALUE)
449 BOOL ok = WriteFile(statusFile, pending,
450 sizeof(pending) - 1, &wrote,
nullptr);
451 CloseHandle(statusFile);
452 return ok && (wrote ==
sizeof(pending) - 1);
464 WCHAR updateStatusFilePath[
MAX_PATH + 1] = { L
'\0' };
465 wcsncpy(updateStatusFilePath, updateDirPath, MAX_PATH);
471 HANDLE statusFile = CreateFileW(updateStatusFilePath, GENERIC_WRITE, 0,
472 nullptr, CREATE_ALWAYS, 0,
nullptr);
473 if (statusFile == INVALID_HANDLE_VALUE)
478 sprintf(failure,
"failed: %d", errorCode);
480 DWORD toWrite = strlen(failure);
482 BOOL ok = WriteFile(statusFile, failure,
483 toWrite, &wrote,
nullptr);
484 CloseHandle(statusFile);
485 return ok && wrote == toWrite;
526 DWORD lastServiceState = 0x000000CF;
529 SC_HANDLE serviceManager = OpenSCManager(
nullptr,
nullptr,
531 SC_MANAGER_ENUMERATE_SERVICE);
534 DWORD lastError = GetLastError();
537 case ERROR_ACCESS_DENIED:
539 case ERROR_DATABASE_DOES_NOT_EXIST:
547 SC_HANDLE service = OpenServiceW(serviceManager,
549 SERVICE_QUERY_STATUS);
552 DWORD lastError = GetLastError();
553 CloseServiceHandle(serviceManager);
556 case ERROR_ACCESS_DENIED:
558 case ERROR_INVALID_HANDLE:
560 case ERROR_INVALID_NAME:
562 case ERROR_SERVICE_DOES_NOT_EXIST:
569 DWORD currentWaitMS = 0;
570 SERVICE_STATUS_PROCESS ssp;
571 ssp.dwCurrentState = lastServiceState;
572 while (currentWaitMS < maxWaitSeconds * 1000)
575 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
576 sizeof(SERVICE_STATUS_PROCESS), &bytesNeeded))
578 DWORD lastError = GetLastError();
581 case ERROR_INVALID_HANDLE:
582 ssp.dwCurrentState = 0x000000D9;
584 case ERROR_ACCESS_DENIED:
585 ssp.dwCurrentState = 0x000000DA;
587 case ERROR_INSUFFICIENT_BUFFER:
588 ssp.dwCurrentState = 0x000000DB;
590 case ERROR_INVALID_PARAMETER:
591 ssp.dwCurrentState = 0x000000DC;
593 case ERROR_INVALID_LEVEL:
594 ssp.dwCurrentState = 0x000000DD;
596 case ERROR_SHUTDOWN_IN_PROGRESS:
597 ssp.dwCurrentState = 0x000000DE;
601 case ERROR_INVALID_SERVICE_CONTROL:
602 case ERROR_SERVICE_CANNOT_ACCEPT_CTRL:
603 case ERROR_SERVICE_NOT_ACTIVE:
608 ssp.dwCurrentState = 0x000000DF;
616 if (ssp.dwCurrentState == SERVICE_STOPPED)
624 lastServiceState = ssp.dwCurrentState;
625 CloseServiceHandle(service);
626 CloseServiceHandle(serviceManager);
627 return lastServiceState;
630#ifndef ONLY_SERVICE_LAUNCHING
642IsProcessRunning(LPCWSTR filename)
645 HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
646 if (INVALID_HANDLE_VALUE == snapshot)
648 return GetLastError();
651 PROCESSENTRY32W processEntry;
652 processEntry.dwSize =
sizeof(PROCESSENTRY32W);
653 if (!Process32FirstW(snapshot, &processEntry))
655 DWORD lastError = GetLastError();
656 CloseHandle(snapshot);
662 if (wcsicmp(filename, processEntry.szExeFile) == 0)
664 CloseHandle(snapshot);
665 return ERROR_SUCCESS;
668 while (Process32NextW(snapshot, &processEntry));
669 CloseHandle(snapshot);
670 return ERROR_NOT_FOUND;
686 DWORD applicationRunningError = WAIT_TIMEOUT;
687 for (DWORD i = 0;
i < maxSeconds;
i++)
689 applicationRunningError = IsProcessRunning(filename);
690 if (ERROR_NOT_FOUND == applicationRunningError)
692 return ERROR_SUCCESS;
697 if (ERROR_SUCCESS == applicationRunningError)
702 return applicationRunningError;
713 HKEY testOnlyFallbackKey;
714 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,
716 KEY_READ | KEY_WOW64_64KEY,
717 &testOnlyFallbackKey) != ERROR_SUCCESS)
722 RegCloseKey(testOnlyFallbackKey);
737 WCHAR rootPath[
MAX_PATH + 1] = { L
'\0' };
738 if (wcslen(file) > MAX_PATH)
743 wcsncpy(rootPath, file, MAX_PATH);
744 PathStripToRootW(rootPath);
745 isLocal = GetDriveTypeW(rootPath) == DRIVE_FIXED;
759GetDWORDValue(HKEY key, LPCWSTR valueName, DWORD &retValue)
761 DWORD regDWORDValueSize =
sizeof(DWORD);
762 LONG retCode = RegQueryValueExW(key, valueName, 0,
nullptr,
763 reinterpret_cast<LPBYTE
>(&retValue),
765 return ERROR_SUCCESS == retCode;
785 LPCWSTR UACBaseRegKey =
786 L
"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\System";
788 LONG retCode = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
791 if (retCode != ERROR_SUCCESS)
797 DWORD secureDesktop = 0;
798 BOOL success = GetDWORDValue(baseKey, L
"ConsentPromptBehaviorAdmin",
801 GetDWORDValue(baseKey, L
"PromptOnSecureDesktop", secureDesktop);
802 isUnpromptedElevation = !consent && !secureDesktop;
804 RegCloseKey(baseKey);
static bool CanUserElevate()
rtl::Reference< ParseManager > manager
int sprintf(char(&s)[N], char const *format, T &&... arguments)
const wchar_t *typedef BOOL
BOOL PathAppendSafe(LPWSTR base, LPCWSTR extra)
BOOL LaunchWinPostProcess(const WCHAR *installationDir, const WCHAR *updateInfoDir, bool forceSync, HANDLE userToken)
BOOL DoesFallbackKeyExist()
BOOL StartServiceUpdate(LPCWSTR installDir)
BOOL IsUnpromptedElevation(BOOL &isUnpromptedElevation)
DWORD WaitForProcessExit(LPCWSTR filename, DWORD maxSeconds)
DWORD StartServiceCommand(int argc, LPCWSTR *argv)
BOOL IsLocalFile(LPCWSTR file, BOOL &isLocal)
DWORD WaitForServiceStop(LPCWSTR serviceName, DWORD maxWaitSeconds)
BOOL WriteStatusPending(LPCWSTR updateDirPath)
#define TEST_ONLY_FALLBACK_KEY_PATH
DWORD LaunchServiceSoftwareUpdateCommand(int argc, LPCWSTR *argv)
BOOL PathGetSiblingFilePath(LPWSTR destinationBuffer, LPCWSTR siblingFilePath, LPCWSTR newFileName)
BOOL WriteStatusFailure(LPCWSTR updateDirPath, int errorCode)