22#pragma comment(lib, "version.lib")
26struct AutoServiceHandle
28 AutoServiceHandle(SC_HANDLE handle):
35 releaseHandle(mHandle);
38 void releaseHandle(SC_HANDLE handle)
40 if (handle !=
nullptr)
41 CloseServiceHandle(handle);
51 return mHandle !=
nullptr;
54 void reset(SC_HANDLE handle =
nullptr)
56 releaseHandle(mHandle);
77 const unsigned int kNumStrings = 1;
79 const char *kServiceKeys =
"MozillaMaintenanceDescription\0";
82 kNumStrings, serviceStrings);
85 serviceStrings[0][0] =
'\0';
108 DWORD fileVersionInfoSize = GetFileVersionInfoSizeW(path, 0);
109 std::unique_ptr<char[]> fileVersionInfo(
new char[fileVersionInfoSize]);
110 if (!GetFileVersionInfoW(path, 0, fileVersionInfoSize,
111 fileVersionInfo.get()))
113 LOG_WARN((
"Could not obtain file info of old service. (%d)",
118 VS_FIXEDFILEINFO *fixedFileInfo =
119 reinterpret_cast<VS_FIXEDFILEINFO *
>(fileVersionInfo.get());
121 if (!VerQueryValueW(fileVersionInfo.get(), L
"\\",
122 reinterpret_cast<LPVOID*
>(&fixedFileInfo), &
size))
124 LOG_WARN((
"Could not query file version info of old service. (%d)",
129 A = HIWORD(fixedFileInfo->dwFileVersionMS);
130 B = LOWORD(fixedFileInfo->dwFileVersionMS);
131 C = HIWORD(fixedFileInfo->dwFileVersionLS);
132 D = LOWORD(fixedFileInfo->dwFileVersionLS);
148 if (!GetModuleFileNameW(
nullptr, updaterINIPath,
149 sizeof(updaterINIPath) /
150 sizeof(updaterINIPath[0])))
152 LOG_WARN((
"Could not obtain module filename when attempting to "
153 "modify service description. (%d)", GetLastError()));
157 if (!PathRemoveFileSpecW(updaterINIPath))
159 LOG_WARN((
"Could not remove file spec when attempting to "
160 "modify service description. (%d)", GetLastError()));
166 LOG_WARN((
"Could not append updater.ini filename when attempting to "
167 "modify service description. (%d)", GetLastError()));
171 if (GetFileAttributesW(updaterINIPath) == INVALID_FILE_ATTRIBUTES)
173 LOG_WARN((
"updater.ini file does not exist, will not modify "
174 "service description. (%d)", GetLastError()));
182 LOG_WARN((
"updater.ini file does not contain a maintenance "
183 "service description."));
188 if (!MultiByteToWideChar(CP_UTF8, 0,
191 sizeof(serviceDescription) /
192 sizeof(serviceDescription[0])))
194 LOG_WARN((
"Could not convert description to wide string format. (%d)",
199 SERVICE_DESCRIPTIONW descriptionConfig;
200 descriptionConfig.lpDescription = serviceDescription;
201 if (!ChangeServiceConfig2W(serviceHandle,
202 SERVICE_CONFIG_DESCRIPTION,
205 LOG_WARN((
"Could not change service config. (%d)", GetLastError()));
209 LOG((
"The service description was updated successfully."));
224 LPCWSTR currentServicePath,
225 BOOL &servicePathWasWrong)
235 size_t currentServicePathLen = wcslen(currentServicePath);
236 bool doesServiceHaveCorrectPath =
237 currentServicePathLen > 2 &&
238 !wcsstr(currentServicePath, L
"maintenanceservice_tmp.exe") &&
239 currentServicePath[0] == L
'\"' &&
240 currentServicePath[currentServicePathLen - 1] == L
'\"';
242 if (doesServiceHaveCorrectPath)
244 LOG((
"The MozillaMaintenance service path is correct."));
245 servicePathWasWrong =
FALSE;
249 LOG((
"The MozillaMaintenance path is NOT correct. It was: %ls",
250 currentServicePath));
252 servicePathWasWrong =
TRUE;
253 WCHAR fixedPath[
MAX_PATH + 1] = { L
'\0' };
254 wcsncpy(fixedPath, currentServicePath,
MAX_PATH);
255 PathUnquoteSpacesW(fixedPath);
256 if (!PathRemoveFileSpecW(fixedPath))
258 LOG_WARN((
"Couldn't remove file spec. (%d)", GetLastError()));
263 LOG_WARN((
"Couldn't append file spec. (%d)", GetLastError()));
266 PathQuoteSpacesW(fixedPath);
269 if (!ChangeServiceConfigW(service, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE,
270 SERVICE_NO_CHANGE, fixedPath,
nullptr,
nullptr,
271 nullptr,
nullptr,
nullptr,
nullptr))
273 LOG_WARN((
"Could not fix service path. (%d)", GetLastError()));
277 LOG((
"Fixed service path to: %ls.", fixedPath));
293 AutoServiceHandle schSCManager(OpenSCManager(
nullptr,
nullptr,
294 SC_MANAGER_ALL_ACCESS));
297 LOG_WARN((
"Could not open service manager. (%d)", GetLastError()));
301 WCHAR newServiceBinaryPath[
MAX_PATH + 1];
302 if (!GetModuleFileNameW(
nullptr, newServiceBinaryPath,
303 sizeof(newServiceBinaryPath) /
304 sizeof(newServiceBinaryPath[0])))
306 LOG_WARN((
"Could not obtain module filename when attempting to "
307 "install service. (%d)",
313 AutoServiceHandle schService(OpenServiceW(schSCManager.get(),
315 SERVICE_ALL_ACCESS));
316 DWORD lastError = GetLastError();
317 if (!schService && ERROR_SERVICE_DOES_NOT_EXIST != lastError)
320 LOG_WARN((
"Could not open service. (%d)", GetLastError()));
332 LOG_WARN((
"Could not reset security ACE on service handle. It might not be "
333 "possible to start the service. This error should never "
334 "happen. (%d)", GetLastError()));
339 if (!QueryServiceConfigW(schService.get(),
nullptr, 0, &bytesNeeded) &&
340 GetLastError() != ERROR_INSUFFICIENT_BUFFER)
342 LOG_WARN((
"Could not determine buffer size for query service config. (%d)",
349 std::unique_ptr<char[]> serviceConfigBuffer(
new char[bytesNeeded]);
350 if (!QueryServiceConfigW(schService.get(),
351 reinterpret_cast<QUERY_SERVICE_CONFIGW*
>(serviceConfigBuffer.get()),
352 bytesNeeded, &bytesNeeded))
354 LOG_WARN((
"Could open service but could not query service config. (%d)",
358 QUERY_SERVICE_CONFIGW &serviceConfig =
359 *
reinterpret_cast<QUERY_SERVICE_CONFIGW*
>(serviceConfigBuffer.get());
362 BOOL servicePathWasWrong;
363 static BOOL alreadyCheckedFixServicePath =
FALSE;
364 if (!alreadyCheckedFixServicePath)
366 if (!
FixServicePath(schService.get(), serviceConfig.lpBinaryPathName,
367 servicePathWasWrong))
369 LOG_WARN((
"Could not fix service path. This should never happen. (%d)",
376 else if (servicePathWasWrong)
383 alreadyCheckedFixServicePath =
TRUE;
384 LOG((
"Restarting install action: %d",
action));
392 PathUnquoteSpacesW(serviceConfig.lpBinaryPathName);
397 DWORD existingA, existingB, existingC, existingD;
398 DWORD newA, newB, newC, newD;
399 BOOL obtainedExistingVersionInfo =
401 existingA, existingB,
402 existingC, existingD);
406 LOG_WARN((
"Could not obtain version number from new path"));
414 !obtainedExistingVersionInfo ||
415 (existingA < newA) ||
416 (existingA == newA && existingB < newB) ||
417 (existingA == newA && existingB == newB &&
419 (existingA == newA && existingB == newB &&
420 existingC == newC && existingD < newD))
432 if (!wcscmp(newServiceBinaryPath, serviceConfig.lpBinaryPathName))
434 LOG((
"File is already in the correct location, no action needed for "
435 "upgrade. The path is: \"%ls\"", newServiceBinaryPath));
444 if (!CopyFileW(newServiceBinaryPath,
445 serviceConfig.lpBinaryPathName,
FALSE))
447 LOG_WARN((
"Could not overwrite old service binary file. "
448 "This should never happen, but if it does the next "
449 "upgrade will fix it, the service is not a critical "
450 "component that needs to be installed for upgrades "
451 "to work. (%d)", GetLastError()));
455 const size_t len = wcslen(serviceConfig.lpBinaryPathName);
460 LPWSTR oldServiceBinaryTempPath =
462 memset(oldServiceBinaryTempPath, 0, (len + 1) *
sizeof (WCHAR));
463 wcsncpy(oldServiceBinaryTempPath, serviceConfig.lpBinaryPathName, len);
465 wcsncpy(oldServiceBinaryTempPath + len - 3, L
"old", 3);
468 if (MoveFileExW(serviceConfig.lpBinaryPathName,
469 oldServiceBinaryTempPath,
470 MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH))
473 if (!CopyFileW(newServiceBinaryPath,
474 serviceConfig.lpBinaryPathName,
FALSE))
477 LOG_WARN((
"The new service binary could not be copied in."
478 " The service will not be upgraded."));
483 LOG((
"The new service binary was copied in by first moving the"
484 " old one out of the way."));
488 if (DeleteFileW(oldServiceBinaryTempPath))
490 LOG((
"The old temp service path was deleted: %ls.",
491 oldServiceBinaryTempPath));
497 LOG_WARN((
"The old temp service path was not deleted."));
503 LOG_WARN((
"Could not move old service file out of the way from:"
504 " \"%ls\" to \"%ls\". Service will not be upgraded. (%d)",
505 serviceConfig.lpBinaryPathName,
506 oldServiceBinaryTempPath, GetLastError()));
509 delete[] oldServiceBinaryTempPath;
514 LOG_WARN((
"Service binary path was less than 3, service will"
515 " not be updated. This should never happen."));
521 LOG((
"The new service binary was copied in."));
527 if (MoveFileExW(newServiceBinaryPath,
nullptr,
528 MOVEFILE_DELAY_UNTIL_REBOOT))
530 LOG((
"Deleting the old file path on the next reboot: %ls.",
531 newServiceBinaryPath));
535 LOG_WARN((
"Call to delete the old file path failed: %ls.",
536 newServiceBinaryPath));
545 MoveFileExW(newServiceBinaryPath,
nullptr, MOVEFILE_DELAY_UNTIL_REBOOT);
559 PathQuoteSpacesW(newServiceBinaryPath);
562 SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS,
563 SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL,
564 newServiceBinaryPath,
nullptr,
nullptr,
565 nullptr,
nullptr,
nullptr));
568 LOG_WARN((
"Could not create Windows service. "
569 "This error should never happen since a service install "
570 "should only be called when elevated. (%d)", GetLastError()));
576 LOG_WARN((
"Could not set security ACE on service handle, the service will not "
577 "be able to be started from unelevated processes. "
578 "This error should never happen. (%d)",
596 AutoServiceHandle schSCManager(OpenSCManager(
nullptr,
nullptr,
597 SC_MANAGER_ALL_ACCESS));
600 LOG_WARN((
"Could not open service manager. (%d)", GetLastError()));
605 AutoServiceHandle schService(OpenServiceW(schSCManager.get(),
SVC_NAME,
606 SERVICE_ALL_ACCESS));
609 LOG_WARN((
"Could not open service. (%d)", GetLastError()));
613 LOG((
"Sending stop request..."));
614 SERVICE_STATUS status;
615 SetLastError(ERROR_SUCCESS);
616 if (!ControlService(schService.get(), SERVICE_CONTROL_STOP, &status) &&
617 GetLastError() != ERROR_SERVICE_NOT_ACTIVE)
619 LOG_WARN((
"Error sending stop request. (%d)", GetLastError()));
622 schSCManager.reset();
625 LOG((
"Waiting for service stop..."));
631 LOG((
"Done waiting for service stop, last service state: %d", lastState));
633 return lastState == SERVICE_STOPPED;
645 AutoServiceHandle schSCManager(OpenSCManager(
nullptr,
nullptr,
646 SC_MANAGER_ALL_ACCESS));
649 LOG_WARN((
"Could not open service manager. (%d)", GetLastError()));
654 AutoServiceHandle schService(OpenServiceW(schSCManager.get(),
SVC_NAME,
655 SERVICE_ALL_ACCESS));
658 LOG_WARN((
"Could not open service. (%d)", GetLastError()));
664 DWORD totalWaitTime = 0;
665 SERVICE_STATUS status;
666 static const int maxWaitTime = 1000 * 60;
667 if (ControlService(schService.get(), SERVICE_CONTROL_STOP, &status))
671 Sleep(status.dwWaitHint);
672 totalWaitTime += (status.dwWaitHint + 10);
673 if (status.dwCurrentState == SERVICE_STOPPED)
677 else if (totalWaitTime > maxWaitTime)
682 while (QueryServiceStatus(schService.get(), &status));
686 BOOL deleted = DeleteService(schService.get());
689 deleted = (GetLastError() == ERROR_SERVICE_MARKED_FOR_DELETE);
704 PACL pNewAcl =
nullptr;
705 PSECURITY_DESCRIPTOR psd =
nullptr;
709 LocalFree((HLOCAL)pNewAcl);
713 LocalFree((LPVOID)psd);
715 return ERROR_SUCCESS == lastError;
728 PSECURITY_DESCRIPTOR psd)
732 if (!QueryServiceObjectSecurity(hService, DACL_SECURITY_INFORMATION,
735 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
737 LOG_WARN((
"Could not query service object security size. (%d)",
739 return GetLastError();
743 psd = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR,
size);
746 LOG_WARN((
"Could not allocate security descriptor. (%d)",
748 return ERROR_INSUFFICIENT_BUFFER;
752 if (!QueryServiceObjectSecurity(hService, DACL_SECURITY_INFORMATION,
755 LOG_WARN((
"Could not allocate security descriptor. (%d)",
757 return GetLastError();
765 if ( !GetSecurityDescriptorDacl(psd, &bDaclPresent, &pacl,
768 LOG_WARN((
"Could not obtain DACL. (%d)", GetLastError()));
769 return GetLastError();
773 DWORD SIDSize = SECURITY_MAX_SID_SIZE;
774 sid = LocalAlloc(LMEM_FIXED, SIDSize);
777 LOG_WARN((
"Could not allocate SID memory. (%d)", GetLastError()));
778 return GetLastError();
781 if (!CreateWellKnownSid(WinBuiltinUsersSid,
nullptr,
sid, &SIDSize))
783 DWORD lastError = GetLastError();
784 LOG_WARN((
"Could not create well known SID. (%d)", lastError));
792 SID_NAME_USE accountType;
793 WCHAR accountName[UNLEN + 1] = { L
'\0' };
794 WCHAR domainName[DNLEN + 1] = { L
'\0' };
795 DWORD accountNameSize = UNLEN + 1;
796 DWORD domainNameSize = DNLEN + 1;
797 if (!LookupAccountSidW(
nullptr,
sid, accountName,
799 domainName, &domainNameSize, &accountType))
801 LOG_WARN((
"Could not lookup account Sid, will try Users. (%d)",
803 wcsncpy(accountName, L
"Users", UNLEN);
812 BuildExplicitAccessWithNameW(&ea, accountName,
813 SERVICE_START | SERVICE_STOP | GENERIC_READ,
814 SET_ACCESS, NO_INHERITANCE);
815 DWORD lastError = SetEntriesInAclW(1, (PEXPLICIT_ACCESS)&ea, pacl, &pNewAcl);
816 if (ERROR_SUCCESS != lastError)
818 LOG_WARN((
"Could not set entries in ACL. (%d)", lastError));
823 SECURITY_DESCRIPTOR
sd;
824 if (!InitializeSecurityDescriptor(&
sd, SECURITY_DESCRIPTOR_REVISION))
826 LOG_WARN((
"Could not initialize security descriptor. (%d)",
828 return GetLastError();
832 if (!SetSecurityDescriptorDacl(&
sd,
TRUE, pNewAcl,
FALSE))
834 LOG_WARN((
"Could not set security descriptor DACL. (%d)",
836 return GetLastError();
840 if (!SetServiceObjectSecurity(hService, DACL_SECURITY_INFORMATION, &
sd))
842 LOG_WARN((
"Could not set object security. (%d)",
844 return GetLastError();
848 LOG((
"User access was set successfully on the service."));
849 return ERROR_SUCCESS;
css::uno::Reference< css::linguistic2::XProofreadingIterator > get(css::uno::Reference< css::uno::XComponentContext > const &context)
int ReadStrings(const NS_tchar *path, const char *keyList, unsigned int numStrings, char results[][MAX_TEXT_LEN], const char *section)
A very basic parser for updater.ini taken mostly from nsINIParser.cpp that can be used by standalone ...
const wchar_t *typedef BOOL
BOOL PathAppendSafe(LPWSTR base, LPCWSTR extra)
BOOL StopService()
Stops the Maintenance service.
BOOL FixServicePath(SC_HANDLE service, LPCWSTR currentServicePath, BOOL &servicePathWasWrong)
Determines if the MozillaMaintenance service path needs to be updated and fixes it if it is wrong.
BOOL UpdateServiceDescription(SC_HANDLE serviceHandle)
Updates the service description with what is stored in updater.ini at the same path as the currently ...
static BOOL GetVersionNumberFromPath(LPWSTR path, DWORD &A, DWORD &B, DWORD &C, DWORD &D)
Obtains the version number from the specified PE file's version information Version Format: A....
static int ReadMaintenanceServiceStrings(LPCWSTR path, MaintenanceServiceStringTable *results)
A wrapper function to read strings for the maintenance service.
BOOL SetUserAccessServiceDACL(SC_HANDLE hService)
Sets the access control list for user access for the specified service.
BOOL SvcInstall(SvcInstallAction action)
Installs or upgrades the SVC_NAME service.
BOOL SvcUninstall()
Uninstalls the Maintenance service.
char serviceDescription[MAX_TEXT_LEN]
DWORD WaitForProcessExit(LPCWSTR filename, DWORD maxSeconds)
DWORD WaitForServiceStop(LPCWSTR serviceName, DWORD maxWaitSeconds)