зеркало из https://github.com/mozilla/pjs.git
Bug 481815 - Provide a Windows service for silent updates. r=rstrong.
This commit is contained in:
Родитель
3434d6d244
Коммит
8011a2a8d9
|
@ -71,6 +71,8 @@ ifdef MOZ_INSTALLER
|
|||
# uninstaller is included with the application for mar file generation.
|
||||
libs::
|
||||
$(MAKE) -C installer/windows uninstaller
|
||||
|
||||
ifdef MOZ_MAINTENANCE_SERVICE
|
||||
$(MAKE) -C installer/windows maintenanceservice_installer
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
|
|
@ -200,6 +200,11 @@ pref("app.update.showInstalledUI", false);
|
|||
// versions.
|
||||
pref("app.update.incompatible.mode", 0);
|
||||
|
||||
// Whether or not to attempt using the service for updates.
|
||||
#ifdef MOZ_MAINTENANCE_SERVICE
|
||||
pref("app.update.service.enabled", true);
|
||||
#endif
|
||||
|
||||
// Symmetric (can be overridden by individual extensions) update preferences.
|
||||
// e.g.
|
||||
// extensions.{GUID}.update.enabled
|
||||
|
|
|
@ -188,9 +188,13 @@ appUpdater.prototype =
|
|||
|
||||
// true when there is an update already staged / ready to be applied.
|
||||
get isPending() {
|
||||
if (this.update)
|
||||
return this.update.state == "pending";
|
||||
return this.um.activeUpdate && this.um.activeUpdate.state == "pending";
|
||||
if (this.update) {
|
||||
return this.update.state == "pending" ||
|
||||
this.update.state == "pending-service";
|
||||
}
|
||||
return this.um.activeUpdate &&
|
||||
(this.um.activeUpdate.state == "pending" ||
|
||||
this.um.activeUpdate.state == "pending-service");
|
||||
},
|
||||
|
||||
// true when there is an update download in progress.
|
||||
|
|
|
@ -531,6 +531,26 @@ var gAdvancedPane = {
|
|||
// the warnIncompatible checkbox value is set by readAddonWarn
|
||||
warnIncompatible.disabled = radiogroup.disabled || modePref.locked ||
|
||||
!enabledPref.value || !autoPref.value;
|
||||
|
||||
#ifdef MOZ_MAINTENANCE_SERVICE
|
||||
// Check to see if the maintenance service is installed.
|
||||
// If it is don't show the preference at all.
|
||||
var installed;
|
||||
try {
|
||||
Components.utils.reportError("0");
|
||||
var wrk = Components.classes["@mozilla.org/windows-registry-key;1"]
|
||||
.createInstance(Components.interfaces.nsIWindowsRegKey);
|
||||
wrk.open(wrk.ROOT_KEY_LOCAL_MACHINE,
|
||||
"SOFTWARE\\Mozilla\\MaintenanceService",
|
||||
wrk.ACCESS_READ | wrk.WOW64_64);
|
||||
installed = wrk.readIntValue("Installed");
|
||||
wrk.close();
|
||||
} catch(e) {
|
||||
}
|
||||
if (installed != 1) {
|
||||
document.getElementById("useService").hidden = true;
|
||||
}
|
||||
#endif
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
@ -108,6 +108,12 @@
|
|||
<preference id="app.update.disable_button.showUpdateHistory"
|
||||
name="app.update.disable_button.showUpdateHistory"
|
||||
type="bool"/>
|
||||
|
||||
#ifdef MOZ_MAINTENANCE_SERVICE
|
||||
<preference id="app.update.service.enabled"
|
||||
name="app.update.service.enabled"
|
||||
type="bool"/>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
<preference id="browser.search.update" name="browser.search.update" type="bool"/>
|
||||
|
@ -336,6 +342,13 @@
|
|||
preference="app.update.disable_button.showUpdateHistory"
|
||||
oncommand="gAdvancedPane.showUpdates();"/>
|
||||
</hbox>
|
||||
|
||||
#ifdef MOZ_MAINTENANCE_SERVICE
|
||||
<checkbox id="useService"
|
||||
label="&useService.label;"
|
||||
accesskey="&useService.accesskey;"
|
||||
preference="app.update.service.enabled"/>
|
||||
#endif
|
||||
</groupbox>
|
||||
#endif
|
||||
<groupbox id="updateOthers">
|
||||
|
|
|
@ -544,6 +544,13 @@ bin/libfreebl_32int64_3.so
|
|||
@BINPATH@/updater@BIN_SUFFIX@
|
||||
#endif
|
||||
|
||||
; [MaintenanceService]
|
||||
;
|
||||
#ifdef MOZ_MAINTENANCE_SERVICE
|
||||
@BINPATH@/maintenanceservice.exe
|
||||
@BINPATH@/maintenanceservice_installer.exe
|
||||
#endif
|
||||
|
||||
; [Crash Reporter]
|
||||
;
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
|
|
|
@ -1452,3 +1452,7 @@ extensions/inspector@mozilla.org/chrome/icons/default/winInspectorMain.ico
|
|||
components/nsPlacesTransactionsService.js
|
||||
components/browserplaces.xpt
|
||||
components/nsPlacesDBFlush.js
|
||||
#ifndef MOZ_MAINTENANCE_SERVICE
|
||||
maintenanceservice.exe
|
||||
maintenanceservice_installer.exe
|
||||
#endif
|
||||
|
|
|
@ -61,6 +61,13 @@ INSTALLER_FILES = \
|
|||
nsis/shared.nsh \
|
||||
$(NULL)
|
||||
|
||||
ifdef MOZ_MAINTENANCE_SERVICE
|
||||
INSTALLER_FILES += \
|
||||
nsis/maintenanceservice_installer.nsi \
|
||||
$(NULL)
|
||||
endif
|
||||
|
||||
|
||||
BRANDING_FILES = \
|
||||
branding.nsi \
|
||||
wizHeader.bmp \
|
||||
|
@ -104,6 +111,17 @@ uninstaller::
|
|||
--preprocess-locale $(topsrcdir) \
|
||||
$(PPL_LOCALE_ARGS) $(AB_CD) $(CONFIG_DIR)
|
||||
|
||||
# For building the maintenanceservice installer
|
||||
ifdef MOZ_MAINTENANCE_SERVICE
|
||||
maintenanceservice_installer::
|
||||
$(INSTALL) $(addprefix $(srcdir)/,$(INSTALLER_FILES)) $(CONFIG_DIR)
|
||||
$(PYTHON) $(topsrcdir)/config/Preprocessor.py -Fsubstitution $(DEFINES) $(ACDEFINES) \
|
||||
$(srcdir)/nsis/defines.nsi.in > $(CONFIG_DIR)/defines.nsi
|
||||
$(PYTHON) $(topsrcdir)/toolkit/mozapps/installer/windows/nsis/preprocess-locale.py \
|
||||
--preprocess-locale $(topsrcdir) \
|
||||
$(PPL_LOCALE_ARGS) $(AB_CD) $(CONFIG_DIR)
|
||||
endif
|
||||
|
||||
$(CONFIG_DIR)/setup.exe::
|
||||
$(RM) -r $(CONFIG_DIR)
|
||||
$(MKDIR) $(CONFIG_DIR)
|
||||
|
|
|
@ -17,6 +17,9 @@
|
|||
|
||||
!define NO_UNINSTALL_SURVEY
|
||||
|
||||
!define CERTIFICATE_NAME "Mozilla Corporation"
|
||||
!define CERTIFICATE_ISSUER "Thawte Code Signing CA - G2"
|
||||
|
||||
# LSP_CATEGORIES is the permitted LSP categories for the application. Each LSP
|
||||
# category value is ANDed together to set multiple permitted categories.
|
||||
# See http://msdn.microsoft.com/en-us/library/ms742253%28VS.85%29.aspx
|
||||
|
@ -43,6 +46,10 @@
|
|||
!define MinSupportedVer "Microsoft Windows 2000"
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_MAINTENANCE_SERVICE
|
||||
!define MOZ_MAINTENANCE_SERVICE
|
||||
#endif
|
||||
|
||||
# File details shared by both the installer and uninstaller
|
||||
VIProductVersion "1.0.0.0"
|
||||
VIAddVersionKey "ProductName" "${BrandShortName}"
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#
|
||||
# Contributor(s):
|
||||
# Robert Strong <robert.bugzilla@gmail.com>
|
||||
# Brian R. Bondy <netzen@gmail.com>
|
||||
#
|
||||
# Alternatively, the contents of this file may be used under the terms of
|
||||
# either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
|
@ -35,11 +36,12 @@
|
|||
# ***** END LICENSE BLOCK *****
|
||||
|
||||
# Required Plugins:
|
||||
# AppAssocReg http://nsis.sourceforge.net/Application_Association_Registration_plug-in
|
||||
# ApplicationID http://nsis.sourceforge.net/ApplicationID_plug-in
|
||||
# CityHash http://mxr.mozilla.org/mozilla-central/source/other-licenses/nsis/Contrib/CityHash
|
||||
# ShellLink http://nsis.sourceforge.net/ShellLink_plug-in
|
||||
# UAC http://nsis.sourceforge.net/UAC_plug-in
|
||||
# AppAssocReg http://nsis.sourceforge.net/Application_Association_Registration_plug-in
|
||||
# ApplicationID http://nsis.sourceforge.net/ApplicationID_plug-in
|
||||
# CityHash http://mxr.mozilla.org/mozilla-central/source/other-licenses/nsis/Contrib/CityHash
|
||||
# ShellLink http://nsis.sourceforge.net/ShellLink_plug-in
|
||||
# UAC http://nsis.sourceforge.net/UAC_plug-in
|
||||
# ServicesHelper Mozilla specific plugin that is located in /other-licenses/nsis
|
||||
|
||||
; Set verbosity to 3 (e.g. no script) to lessen the noise in the build logs
|
||||
!verbose 3
|
||||
|
@ -59,6 +61,7 @@ Var InstallType
|
|||
Var AddStartMenuSC
|
||||
Var AddQuickLaunchSC
|
||||
Var AddDesktopSC
|
||||
Var InstallMaintenanceService
|
||||
Var PageName
|
||||
|
||||
; By defining NO_STARTMENU_DIR an installer that doesn't provide an option for
|
||||
|
@ -111,6 +114,7 @@ VIAddVersionKey "OriginalFilename" "setup.exe"
|
|||
!insertmacro InitHashAppModelId
|
||||
!insertmacro IsHandlerForInstallDir
|
||||
!insertmacro IsPinnedToTaskBar
|
||||
!insertmacro IsUserAdmin
|
||||
!insertmacro LogDesktopShortcut
|
||||
!insertmacro LogQuickLaunchShortcut
|
||||
!insertmacro LogStartMenuShortcut
|
||||
|
@ -183,6 +187,11 @@ Page custom preOptions leaveOptions
|
|||
!define MUI_DIRECTORYPAGE_VERIFYONLEAVE
|
||||
!insertmacro MUI_PAGE_DIRECTORY
|
||||
|
||||
; Custom Components Page
|
||||
!ifdef MOZ_MAINTENANCE_SERVICE
|
||||
Page custom preComponents leaveComponents
|
||||
!endif
|
||||
|
||||
; Custom Shortcuts Page
|
||||
Page custom preShortcuts leaveShortcuts
|
||||
|
||||
|
@ -373,6 +382,37 @@ Section "-Application" APP_IDX
|
|||
${EndIf}
|
||||
${EndIf}
|
||||
|
||||
!ifdef MOZ_MAINTENANCE_SERVICE
|
||||
; If the maintenance service page was displayed then a value was already
|
||||
; explicitly selected for installing the maintenance service and
|
||||
; and so InstallMaintenanceService will already be 0 or 1.
|
||||
; If the maintenance service page was not displayed then
|
||||
; InstallMaintenanceService will be equal to "".
|
||||
${If} $InstallMaintenanceService == ""
|
||||
Call IsUserAdmin
|
||||
Pop $R0
|
||||
${If} $R0 == "true"
|
||||
; Only proceed if we have HKLM write access
|
||||
${AndIf} $TmpVal == "HKLM"
|
||||
; On Windows 2000 we do not install the maintenance service.
|
||||
${AndIf} ${AtLeastWinXP}
|
||||
; The user is an admin so we should default to install service yes
|
||||
StrCpy $InstallMaintenanceService "1"
|
||||
${Else}
|
||||
; The user is not admin so we should default to install service no
|
||||
StrCpy $InstallMaintenanceService "0"
|
||||
${EndIf}
|
||||
${EndIf}
|
||||
|
||||
${If} $InstallMaintenanceService == "1"
|
||||
; The user wants to install the maintenance service, so execute
|
||||
; the pre-packaged maintenance service installer.
|
||||
; This option can only be turned on if the user is an admin so there
|
||||
; is no need to use ExecShell w/ verb runas to enforce elevated.
|
||||
nsExec::Exec "$INSTDIR\maintenanceservice_installer.exe"
|
||||
${EndIf}
|
||||
!endif
|
||||
|
||||
; These need special handling on uninstall since they may be overwritten by
|
||||
; an install into a different location.
|
||||
StrCpy $0 "Software\Microsoft\Windows\CurrentVersion\App Paths\${FileMainEXE}"
|
||||
|
@ -426,7 +466,7 @@ Section "-Application" APP_IDX
|
|||
${Unless} ${Errors}
|
||||
GetFunctionAddress $0 FixShortcutAppModelIDs
|
||||
UAC::ExecCodeSegment $0
|
||||
${EndIf}
|
||||
${EndUnless}
|
||||
|
||||
; UAC only allows elevating to an Admin account so there is no need to add
|
||||
; the Start Menu or Desktop shortcuts from the original unelevated process
|
||||
|
@ -482,6 +522,13 @@ Section "-Application" APP_IDX
|
|||
${EndIf}
|
||||
${EndUnless}
|
||||
${EndIf}
|
||||
|
||||
!ifdef MOZ_MAINTENANCE_SERVICE
|
||||
${If} $TmpVal == "HKLM"
|
||||
; Add the registry keys for allowed certificates.
|
||||
${AddMaintCertKeys}
|
||||
${EndIf}
|
||||
!endif
|
||||
SectionEnd
|
||||
|
||||
; Cleanup operations to perform at the end of the installation.
|
||||
|
@ -799,6 +846,58 @@ Function leaveShortcuts
|
|||
${EndIf}
|
||||
FunctionEnd
|
||||
|
||||
!ifdef MOZ_MAINTENANCE_SERVICE
|
||||
Function preComponents
|
||||
; If the service already exists, don't show this page
|
||||
ServicesHelper::IsInstalled "MozillaMaintenance"
|
||||
Pop $R9
|
||||
${If} $R9 == 1
|
||||
; The service already exists so don't show this page.
|
||||
Abort
|
||||
${EndIf}
|
||||
|
||||
; On Windows 2000 we do not install the maintenance service.
|
||||
${Unless} ${AtLeastWinXP}
|
||||
Abort
|
||||
${EndUnless}
|
||||
|
||||
; Don't show the custom components page if the
|
||||
; user is not an admin
|
||||
Call IsUserAdmin
|
||||
Pop $R9
|
||||
${If} $R9 != "true"
|
||||
Abort
|
||||
${EndIf}
|
||||
|
||||
; Only show the maintenance service page if we have write access to HKLM
|
||||
ClearErrors
|
||||
WriteRegStr HKLM "Software\Mozilla" \
|
||||
"${BrandShortName}InstallerTest" "Write Test"
|
||||
${If} ${Errors}
|
||||
ClearErrors
|
||||
Abort
|
||||
${Else}
|
||||
DeleteRegValue HKLM "Software\Mozilla" "${BrandShortName}InstallerTest"
|
||||
${EndIf}
|
||||
|
||||
StrCpy $PageName "Components"
|
||||
${CheckCustomCommon}
|
||||
!insertmacro MUI_HEADER_TEXT "$(COMPONENTS_PAGE_TITLE)" "$(COMPONENTS_PAGE_SUBTITLE)"
|
||||
!insertmacro MUI_INSTALLOPTIONS_DISPLAY "components.ini"
|
||||
FunctionEnd
|
||||
|
||||
Function leaveComponents
|
||||
${MUI_INSTALLOPTIONS_READ} $0 "components.ini" "Settings" "State"
|
||||
${If} $0 != 0
|
||||
Abort
|
||||
${EndIf}
|
||||
${MUI_INSTALLOPTIONS_READ} $InstallMaintenanceService "components.ini" "Field 2" "State"
|
||||
${If} $InstallType == ${INSTALLTYPE_CUSTOM}
|
||||
Call CheckExistingInstall
|
||||
${EndIf}
|
||||
FunctionEnd
|
||||
!endif
|
||||
|
||||
Function preSummary
|
||||
StrCpy $PageName "Summary"
|
||||
; Setup the summary.ini file for the Custom Summary Page
|
||||
|
@ -934,6 +1033,7 @@ Function .onInit
|
|||
|
||||
!insertmacro InitInstallOptionsFile "options.ini"
|
||||
!insertmacro InitInstallOptionsFile "shortcuts.ini"
|
||||
!insertmacro InitInstallOptionsFile "components.ini"
|
||||
!insertmacro InitInstallOptionsFile "summary.ini"
|
||||
|
||||
WriteINIStr "$PLUGINSDIR\options.ini" "Settings" NumFields "5"
|
||||
|
@ -947,7 +1047,7 @@ Function .onInit
|
|||
|
||||
WriteINIStr "$PLUGINSDIR\options.ini" "Field 2" Type "RadioButton"
|
||||
WriteINIStr "$PLUGINSDIR\options.ini" "Field 2" Text "$(OPTION_STANDARD_RADIO)"
|
||||
WriteINIStr "$PLUGINSDIR\options.ini" "Field 2" Left "15"
|
||||
WriteINIStr "$PLUGINSDIR\options.ini" "Field 2" Left "0"
|
||||
WriteINIStr "$PLUGINSDIR\options.ini" "Field 2" Right "-1"
|
||||
WriteINIStr "$PLUGINSDIR\options.ini" "Field 2" Top "25"
|
||||
WriteINIStr "$PLUGINSDIR\options.ini" "Field 2" Bottom "35"
|
||||
|
@ -956,7 +1056,7 @@ Function .onInit
|
|||
|
||||
WriteINIStr "$PLUGINSDIR\options.ini" "Field 3" Type "RadioButton"
|
||||
WriteINIStr "$PLUGINSDIR\options.ini" "Field 3" Text "$(OPTION_CUSTOM_RADIO)"
|
||||
WriteINIStr "$PLUGINSDIR\options.ini" "Field 3" Left "15"
|
||||
WriteINIStr "$PLUGINSDIR\options.ini" "Field 3" Left "0"
|
||||
WriteINIStr "$PLUGINSDIR\options.ini" "Field 3" Right "-1"
|
||||
WriteINIStr "$PLUGINSDIR\options.ini" "Field 3" Top "55"
|
||||
WriteINIStr "$PLUGINSDIR\options.ini" "Field 3" Bottom "65"
|
||||
|
@ -964,14 +1064,14 @@ Function .onInit
|
|||
|
||||
WriteINIStr "$PLUGINSDIR\options.ini" "Field 4" Type "label"
|
||||
WriteINIStr "$PLUGINSDIR\options.ini" "Field 4" Text "$(OPTION_STANDARD_DESC)"
|
||||
WriteINIStr "$PLUGINSDIR\options.ini" "Field 4" Left "30"
|
||||
WriteINIStr "$PLUGINSDIR\options.ini" "Field 4" Left "15"
|
||||
WriteINIStr "$PLUGINSDIR\options.ini" "Field 4" Right "-1"
|
||||
WriteINIStr "$PLUGINSDIR\options.ini" "Field 4" Top "37"
|
||||
WriteINIStr "$PLUGINSDIR\options.ini" "Field 4" Bottom "57"
|
||||
|
||||
WriteINIStr "$PLUGINSDIR\options.ini" "Field 5" Type "label"
|
||||
WriteINIStr "$PLUGINSDIR\options.ini" "Field 5" Text "$(OPTION_CUSTOM_DESC)"
|
||||
WriteINIStr "$PLUGINSDIR\options.ini" "Field 5" Left "30"
|
||||
WriteINIStr "$PLUGINSDIR\options.ini" "Field 5" Left "15"
|
||||
WriteINIStr "$PLUGINSDIR\options.ini" "Field 5" Right "-1"
|
||||
WriteINIStr "$PLUGINSDIR\options.ini" "Field 5" Top "67"
|
||||
WriteINIStr "$PLUGINSDIR\options.ini" "Field 5" Bottom "87"
|
||||
|
@ -993,7 +1093,7 @@ Function .onInit
|
|||
|
||||
WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 2" Type "checkbox"
|
||||
WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 2" Text "$(ICONS_DESKTOP)"
|
||||
WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 2" Left "15"
|
||||
WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 2" Left "0"
|
||||
WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 2" Right "-1"
|
||||
WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 2" Top "20"
|
||||
WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 2" Bottom "30"
|
||||
|
@ -1002,7 +1102,7 @@ Function .onInit
|
|||
|
||||
WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 3" Type "checkbox"
|
||||
WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 3" Text "$(ICONS_STARTMENU)"
|
||||
WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 3" Left "15"
|
||||
WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 3" Left "0"
|
||||
WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 3" Right "-1"
|
||||
WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 3" Top "40"
|
||||
WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 3" Bottom "50"
|
||||
|
@ -1012,13 +1112,32 @@ Function .onInit
|
|||
${Unless} ${AtLeastWin7}
|
||||
WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 4" Type "checkbox"
|
||||
WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 4" Text "$(ICONS_QUICKLAUNCH)"
|
||||
WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 4" Left "15"
|
||||
WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 4" Left "0"
|
||||
WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 4" Right "-1"
|
||||
WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 4" Top "60"
|
||||
WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 4" Bottom "70"
|
||||
WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 4" State "1"
|
||||
${EndUnless}
|
||||
|
||||
; Setup the components.ini file for the Components Page
|
||||
WriteINIStr "$PLUGINSDIR\components.ini" "Settings" NumFields "2"
|
||||
|
||||
WriteINIStr "$PLUGINSDIR\components.ini" "Field 1" Type "label"
|
||||
WriteINIStr "$PLUGINSDIR\components.ini" "Field 1" Text "$(OPTIONAL_COMPONENTS_DESC)"
|
||||
WriteINIStr "$PLUGINSDIR\components.ini" "Field 1" Left "0"
|
||||
WriteINIStr "$PLUGINSDIR\components.ini" "Field 1" Right "-1"
|
||||
WriteINIStr "$PLUGINSDIR\components.ini" "Field 1" Top "5"
|
||||
WriteINIStr "$PLUGINSDIR\components.ini" "Field 1" Bottom "15"
|
||||
|
||||
WriteINIStr "$PLUGINSDIR\components.ini" "Field 2" Type "checkbox"
|
||||
WriteINIStr "$PLUGINSDIR\components.ini" "Field 2" Text "$(MAINTENANCE_SERVICE_CHECKBOX_DESC)"
|
||||
WriteINIStr "$PLUGINSDIR\components.ini" "Field 2" Left "0"
|
||||
WriteINIStr "$PLUGINSDIR\components.ini" "Field 2" Right "-1"
|
||||
WriteINIStr "$PLUGINSDIR\components.ini" "Field 2" Top "20"
|
||||
WriteINIStr "$PLUGINSDIR\components.ini" "Field 2" Bottom "30"
|
||||
WriteINIStr "$PLUGINSDIR\components.ini" "Field 2" State "1"
|
||||
WriteINIStr "$PLUGINSDIR\components.ini" "Field 2" Flags "GROUP"
|
||||
|
||||
; There must always be a core directory.
|
||||
${GetSize} "$EXEDIR\core\" "/S=0K" $R5 $R7 $R8
|
||||
SectionSetSize ${APP_IDX} $R5
|
||||
|
|
|
@ -0,0 +1,283 @@
|
|||
# ***** BEGIN LICENSE BLOCK *****
|
||||
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public License Version
|
||||
# 1.1 (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
# http://www.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS" basis,
|
||||
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
# for the specific language governing rights and limitations under the
|
||||
# License.
|
||||
#
|
||||
# The Original Code is an NSIS installer for the maintenance service
|
||||
#
|
||||
# The Initial Developer of the Original Code is
|
||||
# Mozilla Foundation.
|
||||
# Portions created by the Initial Developer are Copyright (C) 2011
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Brian R. Bondy <netzen@gmail.com>
|
||||
#
|
||||
# Alternatively, the contents of this file may be used under the terms of
|
||||
# either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
# in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
# of those above. If you wish to allow use of your version of this file only
|
||||
# under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
# use your version of this file under the terms of the MPL, indicate your
|
||||
# decision by deleting the provisions above and replace them with the notice
|
||||
# and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
# the provisions above, a recipient may use your version of this file under
|
||||
# the terms of any one of the MPL, the GPL or the LGPL.
|
||||
#
|
||||
# ***** END LICENSE BLOCK *****
|
||||
|
||||
# Required Plugins:
|
||||
# ServicesHelper Mozilla specific plugin that is located in /other-licenses/nsis
|
||||
|
||||
; Set verbosity to 3 (e.g. no script) to lessen the noise in the build logs
|
||||
!verbose 3
|
||||
|
||||
; 7-Zip provides better compression than the lzma from NSIS so we add the files
|
||||
; uncompressed and use 7-Zip to create a SFX archive of it
|
||||
SetDatablockOptimize on
|
||||
SetCompress off
|
||||
CRCCheck on
|
||||
|
||||
RequestExecutionLevel admin
|
||||
!addplugindir ./
|
||||
|
||||
; Variables
|
||||
Var TempMaintServiceName
|
||||
Var BrandFullNameDA
|
||||
Var BrandFullName
|
||||
|
||||
; Other included files may depend upon these includes!
|
||||
; The following includes are provided by NSIS.
|
||||
!include FileFunc.nsh
|
||||
!include LogicLib.nsh
|
||||
!include MUI.nsh
|
||||
!include WinMessages.nsh
|
||||
!include WinVer.nsh
|
||||
!include WordFunc.nsh
|
||||
|
||||
!insertmacro GetOptions
|
||||
!insertmacro GetParameters
|
||||
!insertmacro GetSize
|
||||
|
||||
; The test slaves use this fallback key to run tests.
|
||||
; And anyone that wants to run tests themselves should already have
|
||||
; this installed.
|
||||
!define FallbackKey \
|
||||
"SOFTWARE\Mozilla\MaintenanceService\3932ecacee736d366d6436db0f55bce4"
|
||||
|
||||
!define CompanyName "Mozilla Corporation"
|
||||
!define BrandFullNameInternal ""
|
||||
|
||||
; The following includes are custom.
|
||||
!include defines.nsi
|
||||
; We keep defines.nsi defined so that we get other things like
|
||||
; the version number, but we redefine BrandFullName
|
||||
!define MaintFullName "Mozilla Maintenance Service"
|
||||
!undef BrandFullName
|
||||
!define BrandFullName "${MaintFullName}"
|
||||
|
||||
!include common.nsh
|
||||
!include locales.nsi
|
||||
|
||||
VIAddVersionKey "FileDescription" "${MaintFullName} Installer"
|
||||
VIAddVersionKey "OriginalFilename" "maintenanceservice_installer.exe"
|
||||
|
||||
Name "${MaintFullName}"
|
||||
OutFile "maintenanceservice_installer.exe"
|
||||
|
||||
; Get installation folder from registry if available
|
||||
InstallDirRegKey HKLM "Software\Mozilla\MaintenanceService" ""
|
||||
|
||||
SetOverwrite on
|
||||
|
||||
!define MaintUninstallKey \
|
||||
"Software\Microsoft\Windows\CurrentVersion\Uninstall\MozillaMaintenanceService"
|
||||
|
||||
; The HAVE_64BIT_OS define also means that we have an x64 build,
|
||||
; not just an x64 OS.
|
||||
!ifdef HAVE_64BIT_OS
|
||||
; See below, we actually abort the install for x64 builds currently.
|
||||
InstallDir "$PROGRAMFILES64\${MaintFullName}\"
|
||||
!else
|
||||
InstallDir "$PROGRAMFILES32\${MaintFullName}\"
|
||||
!endif
|
||||
ShowUnInstDetails nevershow
|
||||
|
||||
################################################################################
|
||||
# Modern User Interface - MUI
|
||||
|
||||
!define MUI_ICON setup.ico
|
||||
!define MUI_UNICON setup.ico
|
||||
!define MUI_WELCOMEPAGE_TITLE_3LINES
|
||||
!define MUI_UNWELCOMEFINISHPAGE_BITMAP wizWatermark.bmp
|
||||
|
||||
;Interface Settings
|
||||
!define MUI_ABORTWARNING
|
||||
|
||||
; Uninstaller Pages
|
||||
!insertmacro MUI_UNPAGE_WELCOME
|
||||
!insertmacro MUI_UNPAGE_INSTFILES
|
||||
!insertmacro MUI_UNPAGE_FINISH
|
||||
|
||||
################################################################################
|
||||
# Language
|
||||
|
||||
!insertmacro MOZ_MUI_LANGUAGE 'baseLocale'
|
||||
!verbose push
|
||||
!verbose 3
|
||||
!include "overrideLocale.nsh"
|
||||
!include "customLocale.nsh"
|
||||
!verbose pop
|
||||
|
||||
; Set this after the locale files to override it if it is in the locale
|
||||
; using " " for BrandingText will hide the "Nullsoft Install System..." branding
|
||||
BrandingText " "
|
||||
|
||||
Function .onInit
|
||||
SetSilent silent
|
||||
!ifdef HAVE_64BIT_OS
|
||||
; We plan to eventually enable 64bit native builds to use the maintenance
|
||||
; service, but for the initial release, to reduce testing and development,
|
||||
; 64-bit builds will not install the maintenanceservice.
|
||||
Abort
|
||||
!endif
|
||||
|
||||
; On Windows 2000 we do not install the maintenance service.
|
||||
; We won't run this installer from the parent installer, but just in case
|
||||
; someone tries to execute it on Windows 2000...
|
||||
${Unless} ${AtLeastWinXP}
|
||||
Abort
|
||||
${EndUnless}
|
||||
FunctionEnd
|
||||
|
||||
Function un.onInit
|
||||
StrCpy $BrandFullNameDA "${MaintFullName}"
|
||||
StrCpy $BrandFullName "${MaintFullName}"
|
||||
FunctionEnd
|
||||
|
||||
Section "MaintenanceService"
|
||||
AllowSkipFiles off
|
||||
|
||||
CreateDirectory $INSTDIR
|
||||
SetOutPath $INSTDIR
|
||||
|
||||
; If the service already exists, then stop it if it is running.
|
||||
ServicesHelper::IsInstalled "MozillaMaintenance"
|
||||
Pop $R9
|
||||
${If} $R9 == 1
|
||||
; Stop the maintenance service so we can overwrite any
|
||||
; binaries that it uses.
|
||||
ServicesHelper::Stop "MozillaMaintenance"
|
||||
${EndIf}
|
||||
|
||||
; If we don't have maintenanceservice.exe already installed
|
||||
; then keep that name. If we do use maintenanceservice_tmp.exe
|
||||
; which will auto install itself when you call it with the install parameter.
|
||||
StrCpy $TempMaintServiceName "maintenanceservice.exe"
|
||||
IfFileExists "$INSTDIR\maintenanceservice.exe" 0 skipAlreadyExists
|
||||
StrCpy $TempMaintServiceName "maintenanceservice_tmp.exe"
|
||||
skipAlreadyExists:
|
||||
|
||||
; We always write out a copy and then decide whether to install it or
|
||||
; not via calling its 'install' cmdline which works by version comparison.
|
||||
CopyFiles "$EXEDIR\maintenanceservice.exe" "$INSTDIR\$TempMaintServiceName"
|
||||
|
||||
; Install the application maintenance service.
|
||||
; If a service already exists, the command line parameter will stop the
|
||||
; service and only install itself if it is newer than the already installed
|
||||
; service. If successful it will remove the old maintenanceservice.exe
|
||||
; and replace it with maintenanceservice_tmp.exe.
|
||||
ClearErrors
|
||||
${GetParameters} $0
|
||||
${GetOptions} "$0" "/Upgrade" $0
|
||||
${If} ${Errors}
|
||||
nsExec::Exec '"$INSTDIR\$TempMaintServiceName" install'
|
||||
${Else}
|
||||
; The upgrade cmdline is the same as install except
|
||||
; It will fail if the service isn't already installed.
|
||||
nsExec::Exec '"$INSTDIR\$TempMaintServiceName" upgrade'
|
||||
${EndIf}
|
||||
|
||||
WriteUninstaller "$INSTDIR\Uninstall.exe"
|
||||
WriteRegStr HKLM "${MaintUninstallKey}" "DisplayName" "${MaintFullName}"
|
||||
WriteRegStr HKLM "${MaintUninstallKey}" "UninstallString" \
|
||||
'"$INSTDIR\uninstall.exe"'
|
||||
WriteRegStr HKLM "${MaintUninstallKey}" "DisplayIcon" \
|
||||
"$INSTDIR\Uninstall.exe,0"
|
||||
WriteRegStr HKLM "${MaintUninstallKey}" "DisplayVersion" "${AppVersion}"
|
||||
WriteRegStr HKLM "${MaintUninstallKey}" "Publisher" "Mozilla"
|
||||
WriteRegStr HKLM "${MaintUninstallKey}" "Comments" \
|
||||
"${BrandFullName} ${AppVersion} (${ARCH} ${AB_CD})"
|
||||
${GetSize} "$INSTDIR" "/S=0K" $R2 $R3 $R4
|
||||
WriteRegDWORD HKLM "${MaintUninstallKey}" "EstimatedSize" $R2
|
||||
|
||||
; Write out that a maintenance service was attempted.
|
||||
; We do this because on upgrades we will check this value and we only
|
||||
; want to install once on the first upgrade to maintenance service.
|
||||
; Also write out that we are currently installed, preferences will check
|
||||
; this value to determine if we should show the service update pref.
|
||||
; Since the Maintenance service can be installed either x86 or x64,
|
||||
; always use the 64-bit registry for checking if an attempt was made.
|
||||
SetRegView 64
|
||||
WriteRegDWORD HKLM "Software\Mozilla\MaintenanceService" "Attempted" 1
|
||||
WriteRegDWORD HKLM "Software\Mozilla\MaintenanceService" "Installed" 1
|
||||
|
||||
; Included here for debug purposes only.
|
||||
; These keys are used to bypass the installation dir is a valid installation
|
||||
; check from the service so that tests can be run.
|
||||
; WriteRegStr HKLM "${FallbackKey}\0" "name" "Mozilla Corporation"
|
||||
; WriteRegStr HKLM "${FallbackKey}\0" "issuer" "Thawte Code Signing CA - G2"
|
||||
SetRegView lastused
|
||||
|
||||
# The Mozilla/updates directory will have an inherited permission
|
||||
# which allows any user to write to it. Work items are written there.
|
||||
SetShellVarContext all
|
||||
CreateDirectory "$APPDATA\Mozilla\updates"
|
||||
SectionEnd
|
||||
|
||||
; By renaming before deleting we improve things slightly in case
|
||||
; there is a file in use error. In this case a new install can happen.
|
||||
Function un.RenameDelete
|
||||
Pop $9
|
||||
; If the .moz-delete file already exists previously, delete it
|
||||
; If it doesn't exist, the call is ignored.
|
||||
; We don't need to pass /REBOOTOK here since it was already marked that way
|
||||
; if it exists.
|
||||
Delete "$9.moz-delete"
|
||||
Rename "$9" "$9.moz-delete"
|
||||
${If} ${Errors}
|
||||
Delete /REBOOTOK "$9"
|
||||
${Else}
|
||||
Delete /REBOOTOK "$9.moz-delete"
|
||||
${EndIf}
|
||||
ClearErrors
|
||||
FunctionEnd
|
||||
|
||||
Section "Uninstall"
|
||||
; Delete the service so that no updates will be attempted
|
||||
nsExec::Exec '"$INSTDIR\maintenanceservice.exe" uninstall'
|
||||
|
||||
Push "$INSTDIR\maintenanceservice.exe"
|
||||
Call un.RenameDelete
|
||||
Push "$INSTDIR\maintenanceservice_tmp.exe"
|
||||
Call un.RenameDelete
|
||||
Push "$INSTDIR\Uninstall.exe"
|
||||
Call un.RenameDelete
|
||||
RMDir /REBOOTOK "$INSTDIR"
|
||||
|
||||
DeleteRegKey HKLM "${MaintUninstallKey}"
|
||||
|
||||
SetRegView 64
|
||||
DeleteRegValue HKLM "Software\Mozilla\MaintenanceService" "Installed"
|
||||
DeleteRegKey HKLM "${FallbackKey}\"
|
||||
SetRegView lastused
|
||||
SectionEnd
|
|
@ -19,6 +19,7 @@
|
|||
#
|
||||
# Contributor(s):
|
||||
# Robert Strong <robert.bugzilla@gmail.com>
|
||||
# Brian R. Bondy <netzen@gmail.com>
|
||||
#
|
||||
# Alternatively, the contents of this file may be used under the terms of
|
||||
# either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
|
@ -105,6 +106,46 @@
|
|||
${CleanVirtualStore}
|
||||
|
||||
${RemoveDeprecatedFiles}
|
||||
|
||||
!ifdef MOZ_MAINTENANCE_SERVICE
|
||||
Call IsUserAdmin
|
||||
Pop $R0
|
||||
${If} $R0 == "true"
|
||||
; Only proceed if we have HKLM write access
|
||||
${AndIf} $TmpVal == "HKLM"
|
||||
; On Windows 2000 we do not install the maintenance service.
|
||||
${AndIf} ${AtLeastWinXP}
|
||||
; Add the registry keys for allowed certificates.
|
||||
${AddMaintCertKeys}
|
||||
|
||||
; We check to see if the maintenance service install was already attempted.
|
||||
; Since the Maintenance service can be installed either x86 or x64,
|
||||
; always use the 64-bit registry for checking if an attempt was made.
|
||||
SetRegView 64
|
||||
ReadRegDWORD $5 HKLM "Software\Mozilla\MaintenanceService" "Attempted"
|
||||
ClearErrors
|
||||
SetRegView lastused
|
||||
|
||||
; If the maintenance service is already installed, do nothing.
|
||||
; The maintenance service will launch:
|
||||
; maintenanceservice_installer.exe /Upgrade to upgrade the maintenance
|
||||
; service if necessary. If the update was done from updater.exe without
|
||||
; the service (i.e. service is failing), updater.exe will do the update of
|
||||
; the service. The reasons we do not do it here is because we don't want
|
||||
; to have to prompt for limited user accounts when the service isn't used
|
||||
; and we currently call the PostUpdate twice, once for the user and once
|
||||
; for the SYSTEM account. Also, this would stop the maintenance service
|
||||
; and we need a return result back to the service when run that way.
|
||||
${If} $5 == ""
|
||||
; An install of maintenance service was never attempted.
|
||||
; We call ExecShell (which is ShellExecute) with the verb "runas"
|
||||
; to ask for elevation if the user isn't already elevated. If the user
|
||||
; is already elevated it will just launch the program.
|
||||
ExecShell "runas" "$INSTDIR\maintenanceservice_installer.exe"
|
||||
${EndIf}
|
||||
${EndIf}
|
||||
!endif
|
||||
|
||||
!macroend
|
||||
!define PostUpdate "!insertmacro PostUpdate"
|
||||
|
||||
|
@ -437,38 +478,51 @@
|
|||
!macro SetUninstallKeys
|
||||
StrCpy $0 "Software\Microsoft\Windows\CurrentVersion\Uninstall\${BrandFullNameInternal} ${AppVersion} (${ARCH} ${AB_CD})"
|
||||
|
||||
StrCpy $2 ""
|
||||
ClearErrors
|
||||
WriteRegStr HKLM "$0" "${BrandShortName}InstallerTest" "Write Test"
|
||||
${If} ${Errors}
|
||||
StrCpy $1 "HKCU"
|
||||
SetShellVarContext current ; Set SHCTX to the current user (e.g. HKCU)
|
||||
; If the uninstall keys already exist in HKLM don't create them in HKCU
|
||||
ClearErrors
|
||||
ReadRegStr $2 "HKLM" $0 "DisplayName"
|
||||
${If} $2 == ""
|
||||
; Otherwise we don't have any keys for this product in HKLM so proceeed
|
||||
; to create them in HKCU. Better handling for this will be done in:
|
||||
; Bug 711044 - Better handling for 2 uninstall icons
|
||||
StrCpy $1 "HKCU"
|
||||
SetShellVarContext current ; Set SHCTX to the current user (e.g. HKCU)
|
||||
${EndIf}
|
||||
ClearErrors
|
||||
${Else}
|
||||
StrCpy $1 "HKLM"
|
||||
SetShellVarContext all ; Set SHCTX to all users (e.g. HKLM)
|
||||
DeleteRegValue HKLM "$0" "${BrandShortName}InstallerTest"
|
||||
${EndIf}
|
||||
|
||||
${GetLongPath} "$INSTDIR" $8
|
||||
${If} $2 == ""
|
||||
${GetLongPath} "$INSTDIR" $8
|
||||
|
||||
; Write the uninstall registry keys
|
||||
${WriteRegStr2} $1 "$0" "Comments" "${BrandFullNameInternal} ${AppVersion} (${ARCH} ${AB_CD})" 0
|
||||
${WriteRegStr2} $1 "$0" "DisplayIcon" "$8\${FileMainEXE},0" 0
|
||||
${WriteRegStr2} $1 "$0" "DisplayName" "${BrandFullNameInternal} ${AppVersion} (${ARCH} ${AB_CD})" 0
|
||||
${WriteRegStr2} $1 "$0" "DisplayVersion" "${AppVersion}" 0
|
||||
${WriteRegStr2} $1 "$0" "InstallLocation" "$8" 0
|
||||
${WriteRegStr2} $1 "$0" "Publisher" "Mozilla" 0
|
||||
${WriteRegStr2} $1 "$0" "UninstallString" "$8\uninstall\helper.exe" 0
|
||||
${WriteRegStr2} $1 "$0" "URLInfoAbout" "${URLInfoAbout}" 0
|
||||
${WriteRegStr2} $1 "$0" "URLUpdateInfo" "${URLUpdateInfo}" 0
|
||||
${WriteRegDWORD2} $1 "$0" "NoModify" 1 0
|
||||
${WriteRegDWORD2} $1 "$0" "NoRepair" 1 0
|
||||
; Write the uninstall registry keys
|
||||
${WriteRegStr2} $1 "$0" "Comments" "${BrandFullNameInternal} ${AppVersion} (${ARCH} ${AB_CD})" 0
|
||||
${WriteRegStr2} $1 "$0" "DisplayIcon" "$8\${FileMainEXE},0" 0
|
||||
${WriteRegStr2} $1 "$0" "DisplayName" "${BrandFullNameInternal} ${AppVersion} (${ARCH} ${AB_CD})" 0
|
||||
${WriteRegStr2} $1 "$0" "DisplayVersion" "${AppVersion}" 0
|
||||
${WriteRegStr2} $1 "$0" "InstallLocation" "$8" 0
|
||||
${WriteRegStr2} $1 "$0" "Publisher" "Mozilla" 0
|
||||
${WriteRegStr2} $1 "$0" "UninstallString" "$8\uninstall\helper.exe" 0
|
||||
${WriteRegStr2} $1 "$0" "URLInfoAbout" "${URLInfoAbout}" 0
|
||||
${WriteRegStr2} $1 "$0" "URLUpdateInfo" "${URLUpdateInfo}" 0
|
||||
${WriteRegDWORD2} $1 "$0" "NoModify" 1 0
|
||||
${WriteRegDWORD2} $1 "$0" "NoRepair" 1 0
|
||||
|
||||
${GetSize} "$8" "/S=0K" $R2 $R3 $R4
|
||||
${WriteRegDWORD2} $1 "$0" "EstimatedSize" $R2 0
|
||||
${GetSize} "$8" "/S=0K" $R2 $R3 $R4
|
||||
${WriteRegDWORD2} $1 "$0" "EstimatedSize" $R2 0
|
||||
|
||||
${If} "$TmpVal" == "HKLM"
|
||||
SetShellVarContext all ; Set SHCTX to all users (e.g. HKLM)
|
||||
${Else}
|
||||
SetShellVarContext current ; Set SHCTX to the current user (e.g. HKCU)
|
||||
${If} "$TmpVal" == "HKLM"
|
||||
SetShellVarContext all ; Set SHCTX to all users (e.g. HKLM)
|
||||
${Else}
|
||||
SetShellVarContext current ; Set SHCTX to the current user (e.g. HKCU)
|
||||
${EndIf}
|
||||
${EndIf}
|
||||
!macroend
|
||||
!define SetUninstallKeys "!insertmacro SetUninstallKeys"
|
||||
|
@ -547,6 +601,35 @@
|
|||
!macroend
|
||||
!define UpdateProtocolHandlers "!insertmacro UpdateProtocolHandlers"
|
||||
|
||||
!ifdef MOZ_MAINTENANCE_SERVICE
|
||||
; Adds maintenance service certificate keys for the install dir.
|
||||
; For the cert to work, it must also be signed by a trusted cert for the user.
|
||||
!macro AddMaintCertKeys
|
||||
Push $R0
|
||||
; Allow main Mozilla cert information for updates
|
||||
; This call will push the needed key on the stack
|
||||
ServicesHelper::PathToUniqueRegistryPath "$INSTDIR"
|
||||
Pop $R0
|
||||
${If} $R0 != ""
|
||||
; More than one certificate can be specified in a different subfolder
|
||||
; for example: $R0\1, but each individual binary can be signed
|
||||
; with at most one certificate. A fallback certificate can only be used
|
||||
; if the binary is replaced with a different certificate.
|
||||
; We always use the 64bit registry for certs.
|
||||
; This call is ignored on 32-bit systems.
|
||||
SetRegView 64
|
||||
DeleteRegKey HKLM "$R0"
|
||||
WriteRegStr HKLM "$R0\0" "name" "${CERTIFICATE_NAME}"
|
||||
WriteRegStr HKLM "$R0\0" "issuer" "${CERTIFICATE_ISSUER}"
|
||||
SetRegView lastused
|
||||
ClearErrors
|
||||
${EndIf}
|
||||
; Restore the previously used value back
|
||||
Pop $R0
|
||||
!macroend
|
||||
!define AddMaintCertKeys "!insertmacro AddMaintCertKeys"
|
||||
!endif
|
||||
|
||||
; Removes various registry entries for reasons noted below (does not use SHCTX).
|
||||
!macro RemoveDeprecatedKeys
|
||||
StrCpy $0 "SOFTWARE\Classes"
|
||||
|
@ -1020,7 +1103,6 @@ Function SetAsDefaultAppUserHKCU
|
|||
${EndUnless}
|
||||
${EndIf}
|
||||
${RemoveDeprecatedKeys}
|
||||
|
||||
${PinToTaskBar}
|
||||
FunctionEnd
|
||||
|
||||
|
|
|
@ -61,6 +61,7 @@ RequestExecutionLevel user
|
|||
!define NO_LOG
|
||||
|
||||
Var TmpVal
|
||||
Var MaintCertKey
|
||||
|
||||
; Other included files may depend upon these includes!
|
||||
; The following includes are provided by NSIS.
|
||||
|
@ -96,6 +97,7 @@ VIAddVersionKey "OriginalFilename" "helper.exe"
|
|||
!insertmacro InitHashAppModelId
|
||||
!insertmacro IsHandlerForInstallDir
|
||||
!insertmacro IsPinnedToTaskBar
|
||||
!insertmacro IsUserAdmin
|
||||
!insertmacro LogDesktopShortcut
|
||||
!insertmacro LogQuickLaunchShortcut
|
||||
!insertmacro LogStartMenuShortcut
|
||||
|
@ -380,6 +382,21 @@ Section "Uninstall"
|
|||
; removed and other ugly things will happen like recreation of the app's
|
||||
; clients registry key by the OS under some conditions.
|
||||
System::Call "shell32::SHChangeNotify(i, i, i, i) v (0x08000000, 0, 0, 0)"
|
||||
|
||||
!ifdef MOZ_MAINTENANCE_SERVICE
|
||||
; Get the path the allowed cert is at and remove it
|
||||
; Keep this block of code last since it modfies the reg view
|
||||
ServicesHelper::PathToUniqueRegistryPath "$INSTDIR"
|
||||
Pop $MaintCertKey
|
||||
${If} $MaintCertKey != ""
|
||||
; We always use the 64bit registry for certs
|
||||
; This call is ignored on 32-bit systems.
|
||||
SetRegView 64
|
||||
DeleteRegKey HKLM "$MaintCertKey\"
|
||||
SetRegView lastused
|
||||
${EndIf}
|
||||
!endif
|
||||
|
||||
SectionEnd
|
||||
|
||||
################################################################################
|
||||
|
|
|
@ -0,0 +1,274 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is an NSIS plugin for managing Windows NT services.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Brian R. Bondy <netzen@gmail.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include <windows.h>
|
||||
#include "../../../../toolkit/components/maintenanceservice/pathhash.h"
|
||||
|
||||
#pragma comment(lib, "advapi32.lib")
|
||||
|
||||
typedef struct _stack_t {
|
||||
struct _stack_t *next;
|
||||
TCHAR text[MAX_PATH];
|
||||
} stack_t;
|
||||
|
||||
int popstring(stack_t **stacktop, LPTSTR str, int len);
|
||||
void pushstring(stack_t **stacktop, LPCTSTR str, int len);
|
||||
|
||||
/**
|
||||
* Determines if the specified service exists or not
|
||||
*
|
||||
* @param serviceName The name of the service to check
|
||||
* @param exists Whether or not the service exists
|
||||
* @return TRUE if there were no errors
|
||||
*/
|
||||
static BOOL
|
||||
IsServiceInstalled(LPCWSTR serviceName, BOOL &exists)
|
||||
{
|
||||
exists = FALSE;
|
||||
|
||||
// Get a handle to the local computer SCM database with full access rights.
|
||||
SC_HANDLE serviceManager = OpenSCManager(NULL, NULL,
|
||||
SC_MANAGER_ENUMERATE_SERVICE);
|
||||
if (!serviceManager) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
SC_HANDLE serviceHandle = OpenServiceW(serviceManager,
|
||||
serviceName,
|
||||
SERVICE_QUERY_CONFIG);
|
||||
if (!serviceHandle && GetLastError() != ERROR_SERVICE_DOES_NOT_EXIST) {
|
||||
CloseServiceHandle(serviceManager);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (serviceHandle) {
|
||||
CloseServiceHandle(serviceHandle);
|
||||
exists = TRUE;
|
||||
}
|
||||
|
||||
CloseServiceHandle(serviceManager);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the specified service is installed or not
|
||||
*
|
||||
* @param stacktop A pointer to the top of the stack
|
||||
* @param variables A pointer to the NSIS variables
|
||||
* @return 0 if the service does not exist
|
||||
* 1 if the service does exist
|
||||
* -1 if there was an error.
|
||||
*/
|
||||
extern "C" void __declspec(dllexport)
|
||||
IsInstalled(HWND hwndParent, int string_size,
|
||||
TCHAR *variables, stack_t **stacktop, void *extra)
|
||||
{
|
||||
TCHAR tmp[MAX_PATH] = { L'\0' };
|
||||
WCHAR serviceName[MAX_PATH] = { '\0' };
|
||||
popstring(stacktop, tmp, MAX_PATH);
|
||||
|
||||
#if !defined(UNICODE)
|
||||
MultiByteToWideChar(CP_ACP, 0, tmp, -1, serviceName, MAX_PATH);
|
||||
#else
|
||||
wcscpy(serviceName, tmp);
|
||||
#endif
|
||||
|
||||
BOOL serviceInstalled;
|
||||
if (!IsServiceInstalled(serviceName, serviceInstalled)) {
|
||||
pushstring(stacktop, TEXT("-1"), 3);
|
||||
} else {
|
||||
pushstring(stacktop, serviceInstalled ? TEXT("1") : TEXT("0"), 2);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops the specified service.
|
||||
*
|
||||
* @param serviceName The name of the service to stop
|
||||
* @return TRUE if the operation was successful
|
||||
*/
|
||||
static BOOL
|
||||
StopService(LPCWSTR serviceName)
|
||||
{
|
||||
// Get a handle to the local computer SCM database with full access rights.
|
||||
SC_HANDLE serviceManager = OpenSCManager(NULL, NULL,
|
||||
SC_MANAGER_ENUMERATE_SERVICE);
|
||||
if (!serviceManager) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
SC_HANDLE serviceHandle = OpenServiceW(serviceManager,
|
||||
serviceName,
|
||||
SERVICE_STOP);
|
||||
if (!serviceHandle) {
|
||||
CloseServiceHandle(serviceManager);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
//Stop the service so it deletes faster and so the uninstaller
|
||||
// can actually delete its EXE.
|
||||
DWORD totalWaitTime = 0;
|
||||
SERVICE_STATUS status;
|
||||
static const int maxWaitTime = 1000 * 60; // Never wait more than a minute
|
||||
BOOL stopped = FALSE;
|
||||
if (ControlService(serviceHandle, SERVICE_CONTROL_STOP, &status)) {
|
||||
do {
|
||||
Sleep(status.dwWaitHint);
|
||||
// + 10 milliseconds to make sure we always approach maxWaitTime
|
||||
totalWaitTime += (status.dwWaitHint + 10);
|
||||
if (status.dwCurrentState == SERVICE_STOPPED) {
|
||||
stopped = true;
|
||||
break;
|
||||
} else if (totalWaitTime > maxWaitTime) {
|
||||
break;
|
||||
}
|
||||
} while (QueryServiceStatus(serviceHandle, &status));
|
||||
}
|
||||
|
||||
CloseServiceHandle(serviceHandle);
|
||||
CloseServiceHandle(serviceManager);
|
||||
return stopped;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops the specified service
|
||||
*
|
||||
* @param stacktop A pointer to the top of the stack
|
||||
* @param variables A pointer to the NSIS variables
|
||||
* @return 1 if the service was stopped, 0 on error
|
||||
*/
|
||||
extern "C" void __declspec(dllexport)
|
||||
Stop(HWND hwndParent, int string_size,
|
||||
TCHAR *variables, stack_t **stacktop, void *extra)
|
||||
{
|
||||
TCHAR tmp[MAX_PATH] = { L'\0' };
|
||||
WCHAR serviceName[MAX_PATH] = { '\0' };
|
||||
|
||||
popstring(stacktop, tmp, MAX_PATH);
|
||||
|
||||
#if !defined(UNICODE)
|
||||
MultiByteToWideChar(CP_ACP, 0, tmp, -1, serviceName, MAX_PATH);
|
||||
#else
|
||||
wcscpy(serviceName, tmp);
|
||||
#endif
|
||||
|
||||
if (StopService(serviceName)) {
|
||||
pushstring(stacktop, TEXT("1"), 2);
|
||||
} else {
|
||||
pushstring(stacktop, TEXT("0"), 2);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines a unique registry path from a file or directory path
|
||||
*
|
||||
* @param stacktop A pointer to the top of the stack
|
||||
* @param variables A pointer to the NSIS variables
|
||||
* @return The unique registry path or an empty string on error
|
||||
*/
|
||||
extern "C" void __declspec(dllexport)
|
||||
PathToUniqueRegistryPath(HWND hwndParent, int string_size,
|
||||
TCHAR *variables, stack_t **stacktop,
|
||||
void *extra)
|
||||
{
|
||||
TCHAR tmp[MAX_PATH] = { L'\0' };
|
||||
WCHAR installBasePath[MAX_PATH] = { '\0' };
|
||||
popstring(stacktop, tmp, MAX_PATH);
|
||||
|
||||
#if !defined(UNICODE)
|
||||
MultiByteToWideChar(CP_ACP, 0, tmp, -1, installBasePath, MAX_PATH);
|
||||
#else
|
||||
wcscpy(installBasePath, tmp);
|
||||
#endif
|
||||
|
||||
WCHAR registryPath[MAX_PATH + 1] = { '\0' };
|
||||
if (CalculateRegistryPathFromFilePath(installBasePath, registryPath)) {
|
||||
pushstring(stacktop, registryPath, wcslen(registryPath) + 1);
|
||||
} else {
|
||||
pushstring(stacktop, TEXT(""), 1);
|
||||
}
|
||||
}
|
||||
|
||||
BOOL WINAPI
|
||||
DllMain(HANDLE hInst, ULONG ul_reason_for_call, LPVOID lpReserved)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes an element from the top of the NSIS stack
|
||||
*
|
||||
* @param stacktop A pointer to the top of the stack
|
||||
* @param str The string to pop to
|
||||
* @param len The max length
|
||||
* @return 0 on success
|
||||
*/
|
||||
int popstring(stack_t **stacktop, TCHAR *str, int len)
|
||||
{
|
||||
// Removes the element from the top of the stack and puts it in the buffer
|
||||
stack_t *th;
|
||||
if (!stacktop || !*stacktop) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
th = (*stacktop);
|
||||
lstrcpyn(str,th->text, len);
|
||||
*stacktop = th->next;
|
||||
GlobalFree((HGLOBAL)th);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an element to the top of the NSIS stack
|
||||
*
|
||||
* @param stacktop A pointer to the top of the stack
|
||||
* @param str The string to push on the stack
|
||||
* @param len The length of the string to push on the stack
|
||||
* @return 0 on success
|
||||
*/
|
||||
void pushstring(stack_t **stacktop, const TCHAR *str, int len)
|
||||
{
|
||||
stack_t *th;
|
||||
if (!stacktop) {
|
||||
return;
|
||||
}
|
||||
|
||||
th = (stack_t*)GlobalAlloc(GPTR, sizeof(stack_t) + len);
|
||||
lstrcpyn(th->text, str, len);
|
||||
th->next = *stacktop;
|
||||
*stacktop = th;
|
||||
}
|
|
@ -0,0 +1,115 @@
|
|||
# Microsoft Developer Studio Project File - Name="ServicesHelper" - Package Owner=<4>
|
||||
# Microsoft Developer Studio Generated Build File, Format Version 6.00
|
||||
# ** DO NOT EDIT **
|
||||
|
||||
# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
|
||||
|
||||
CFG=ServicesHelper - Win32 Debug
|
||||
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
|
||||
!MESSAGE use the Export Makefile command and run
|
||||
!MESSAGE
|
||||
!MESSAGE NMAKE /f "ServicesHelper.mak".
|
||||
!MESSAGE
|
||||
!MESSAGE You can specify a configuration when running NMAKE
|
||||
!MESSAGE by defining the macro CFG on the command line. For example:
|
||||
!MESSAGE
|
||||
!MESSAGE NMAKE /f "ServicesHelper.mak" CFG="ServicesHelper - Win32 Debug"
|
||||
!MESSAGE
|
||||
!MESSAGE Possible choices for configuration are:
|
||||
!MESSAGE
|
||||
!MESSAGE "ServicesHelper - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
|
||||
!MESSAGE "ServicesHelper - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
|
||||
!MESSAGE
|
||||
|
||||
# Begin Project
|
||||
# PROP AllowPerConfigDependencies 0
|
||||
# PROP Scc_ProjName ""
|
||||
# PROP Scc_LocalPath ""
|
||||
CPP=cl.exe
|
||||
MTL=midl.exe
|
||||
RSC=rc.exe
|
||||
|
||||
!IF "$(CFG)" == "ServicesHelper - Win32 Release"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 0
|
||||
# PROP BASE Output_Dir "Release"
|
||||
# PROP BASE Intermediate_Dir "Release"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 0
|
||||
# PROP Output_Dir "Release"
|
||||
# PROP Intermediate_Dir "Release"
|
||||
# PROP Ignore_Export_Lib 0
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "EXDLL_EXPORTS" /YX /FD /c
|
||||
# ADD CPP /nologo /MT /W3 /GX /O1 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_UNICODE" /D "UNICODE" /D "_USRDLL" /D "EXDLL_EXPORTS" /D _WIN32_WINNT=0x0400 /FR /YX /FD /c
|
||||
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
|
||||
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
|
||||
# ADD BASE RSC /l 0x409 /d "NDEBUG"
|
||||
# ADD RSC /l 0x409 /d "NDEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
|
||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib MSVCRT.LIB /nologo /entry:"DllMain" /dll /machine:I386 /nodefaultlib /out:"../../Plugins/ServicesHelper.dll" /opt:nowin98
|
||||
# SUBTRACT LINK32 /pdb:none
|
||||
|
||||
!ELSEIF "$(CFG)" == "ServicesHelper - Win32 Debug"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 1
|
||||
# PROP BASE Output_Dir "Debug"
|
||||
# PROP BASE Intermediate_Dir "Debug"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 1
|
||||
# PROP Output_Dir "Debug"
|
||||
# PROP Intermediate_Dir "Debug"
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "EXDLL_EXPORTS" /YX /FD /GZ /c
|
||||
# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "EXDLL_EXPORTS" /YX /FD /GZ /c
|
||||
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
|
||||
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
|
||||
# ADD BASE RSC /l 0x409 /d "_DEBUG"
|
||||
# ADD RSC /l 0x409 /d "_DEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
|
||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
|
||||
|
||||
!ENDIF
|
||||
|
||||
# Begin Target
|
||||
|
||||
# Name "ServicesHelper - Win32 Release"
|
||||
# Name "ServicesHelper - Win32 Debug"
|
||||
# Begin Group "Source Files"
|
||||
|
||||
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=\toolkit\components\maintenanceservice\pathhash.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=\toolkit\components\maintenanceservice\pathhash.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\Services.cpp
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "Header Files"
|
||||
|
||||
# PROP Default_Filter "h;hpp;hxx;hm;inl"
|
||||
# End Group
|
||||
# Begin Group "Resource Files"
|
||||
|
||||
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
|
||||
# End Group
|
||||
# End Target
|
||||
# End Project
|
|
@ -0,0 +1,29 @@
|
|||
Microsoft Developer Studio Workspace File, Format Version 6.00
|
||||
# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
|
||||
|
||||
###############################################################################
|
||||
|
||||
Project: "ServicesHelper"=.\ServicesHelper.dsp - Package Owner=<4>
|
||||
|
||||
Package=<5>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
Package=<4>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
###############################################################################
|
||||
|
||||
Global:
|
||||
|
||||
Package=<5>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
Package=<3>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
###############################################################################
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
// Microsoft Visual C++ generated resource script.
|
||||
//
|
||||
#include "resource.h"
|
||||
|
||||
#define APSTUDIO_READONLY_SYMBOLS
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 2 resource.
|
||||
//
|
||||
#include "afxres.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#undef APSTUDIO_READONLY_SYMBOLS
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// English (United States) resources
|
||||
|
||||
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
|
||||
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||
#pragma code_page(1252)
|
||||
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// TEXTINCLUDE
|
||||
//
|
||||
|
||||
1 TEXTINCLUDE
|
||||
BEGIN
|
||||
"resource.h\0"
|
||||
END
|
||||
|
||||
2 TEXTINCLUDE
|
||||
BEGIN
|
||||
"#include ""afxres.h""\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
3 TEXTINCLUDE
|
||||
BEGIN
|
||||
"\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
#endif // APSTUDIO_INVOKED
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Version
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 1,0,0,0
|
||||
PRODUCTVERSION 1,0,0,0
|
||||
FILEFLAGSMASK 0x17L
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
#else
|
||||
FILEFLAGS 0x0L
|
||||
#endif
|
||||
FILEOS 0x4L
|
||||
FILETYPE 0x2L
|
||||
FILESUBTYPE 0x0L
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "040904b0"
|
||||
BEGIN
|
||||
VALUE "FileDescription", "NSIS Plug-in for managing Windows services"
|
||||
VALUE "FileVersion", "1, 0, 0, 0"
|
||||
VALUE "InternalName", "ServicesHelper"
|
||||
VALUE "LegalCopyright", "MPL 1.1+/GPL 2.0+/LGPL 2.1+"
|
||||
VALUE "OriginalFilename", "ServicesHelper.dll"
|
||||
VALUE "ProductName", "ServicesHelper"
|
||||
VALUE "ProductVersion", "1, 0, 0, 0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x409, 1200
|
||||
END
|
||||
END
|
||||
|
||||
#endif // English (United States) resources
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
#ifndef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 3 resource.
|
||||
//
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#endif // not APSTUDIO_INVOKED
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 9.00
|
||||
# Visual Studio 2005
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ServicesHelper", "ServicesHelper.vcproj", "{A0D0AD52-1D8B-402E-92EF-81AE0C320BD7}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Win32 = Debug|Win32
|
||||
Release|Win32 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{A0D0AD52-1D8B-402E-92EF-81AE0C320BD7}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{A0D0AD52-1D8B-402E-92EF-81AE0C320BD7}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{A0D0AD52-1D8B-402E-92EF-81AE0C320BD7}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{A0D0AD52-1D8B-402E-92EF-81AE0C320BD7}.Release|Win32.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
|
@ -0,0 +1,212 @@
|
|||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="8.00"
|
||||
Name="ServicesHelper"
|
||||
ProjectGUID="{A0D0AD52-1D8B-402E-92EF-81AE0C320BD7}"
|
||||
RootNamespace="ServicesHelper"
|
||||
Keyword="Win32Proj"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="../../Plugins"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="2"
|
||||
CharacterSet="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
AdditionalIncludeDirectories="../../../../toolkit/components/maintenanceservice/"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;APPLICATIONID_EXPORTS"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="3"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="true"
|
||||
DebugInformationFormat="4"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="2"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="2"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="../../Plugins"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="2"
|
||||
ATLMinimizesCRunTimeLibraryUsage="true"
|
||||
CharacterSet="1"
|
||||
WholeProgramOptimization="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
AdditionalIncludeDirectories="../../../../toolkit/components/maintenanceservice/"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;APPLICATIONID_EXPORTS"
|
||||
RuntimeLibrary="0"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="true"
|
||||
DebugInformationFormat="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="1"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="2"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="2"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<Filter
|
||||
Name="Source Files"
|
||||
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
|
||||
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\..\..\..\toolkit\components\maintenanceservice\pathhash.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Services.cpp"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Header Files"
|
||||
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
||||
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
|
||||
>
|
||||
<File
|
||||
RelativePath=".\resource.h"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Resource Files"
|
||||
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
|
||||
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
|
||||
>
|
||||
<File
|
||||
RelativePath=".\ServicesHelper.rc"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
|
@ -0,0 +1,14 @@
|
|||
//{{NO_DEPENDENCIES}}
|
||||
// Microsoft Visual C++ generated include file.
|
||||
// Used by ServicesHelper.rc
|
||||
|
||||
// Next default values for new objects
|
||||
//
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||
#define _APS_NEXT_RESOURCE_VALUE 101
|
||||
#define _APS_NEXT_COMMAND_VALUE 40001
|
||||
#define _APS_NEXT_CONTROL_VALUE 1001
|
||||
#define _APS_NEXT_SYMED_VALUE 101
|
||||
#endif
|
||||
#endif
|
Двоичный файл не отображается.
|
@ -55,12 +55,21 @@ PARALLEL_DIRS = \
|
|||
mozapps/preferences \
|
||||
mozapps/plugins \
|
||||
mozapps/shared \
|
||||
mozapps/update \
|
||||
obsolete \
|
||||
profile \
|
||||
themes \
|
||||
$(NULL)
|
||||
|
||||
DIRS += \
|
||||
mozapps/update \
|
||||
$(NULL)
|
||||
|
||||
ifdef MOZ_MAINTENANCE_SERVICE
|
||||
DIRS += \
|
||||
components/maintenanceservice \
|
||||
$(NULL)
|
||||
endif
|
||||
|
||||
ifneq (,$(filter gtk2 qt,$(MOZ_WIDGET_TOOLKIT)))
|
||||
PARALLEL_DIRS += system/unixproxy
|
||||
endif
|
||||
|
|
|
@ -0,0 +1,100 @@
|
|||
# ***** BEGIN LICENSE BLOCK *****
|
||||
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public License Version
|
||||
# 1.1 (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
# http://www.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS" basis,
|
||||
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
# for the specific language governing rights and limitations under the
|
||||
# License.
|
||||
#
|
||||
# The Original Code is Mozilla maintenance service build.
|
||||
#
|
||||
# The Initial Developer of the Original Code is
|
||||
# Mozilla Foundation.
|
||||
# Portions created by the Initial Developer are Copyright (C) 2011
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Brian R. Bondy <netzen@gmail.com>
|
||||
#
|
||||
# Alternatively, the contents of this file may be used under the terms of
|
||||
# either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
# in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
# of those above. If you wish to allow use of your version of this file only
|
||||
# under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
# use your version of this file under the terms of the MPL, indicate your
|
||||
# decision by deleting the provisions above and replace them with the notice
|
||||
# and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
# the provisions above, a recipient may use your version of this file under
|
||||
# the terms of any one of the MPL, the GPL or the LGPL.
|
||||
#
|
||||
# ***** END LICENSE BLOCK *****
|
||||
|
||||
DEPTH = ../../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
CPPSRCS = \
|
||||
maintenanceservice.cpp \
|
||||
serviceinstall.cpp \
|
||||
workmonitor.cpp \
|
||||
certificatecheck.cpp \
|
||||
servicebase.cpp \
|
||||
registrycertificates.cpp \
|
||||
pathhash.cpp \
|
||||
$(NULL)
|
||||
|
||||
# For debugging purposes only
|
||||
#DEFINES += -DDISABLE_SERVICE_AUTHENTICODE_CHECK \
|
||||
# -DDISABLE_CALLBACK_AUTHENTICODE_CHECK
|
||||
|
||||
PROGRAM = maintenanceservice$(BIN_SUFFIX)
|
||||
DIST_PROGRAM = maintenanceservice$(BIN_SUFFIX)
|
||||
|
||||
# Don't link the maintenanceservice against libmozutils. See bug 687139
|
||||
MOZ_UTILS_LDFLAGS =
|
||||
MOZ_UTILS_PROGRAM_LDFLAGS =
|
||||
|
||||
LIBS += \
|
||||
../../mozapps/update/common/$(LIB_PREFIX)updatecommon.$(LIB_SUFFIX) \
|
||||
$(NULL)
|
||||
|
||||
USE_STATIC_LIBS = 1
|
||||
HAVE_PROGRESSUI = 1
|
||||
RCINCLUDE = maintenanceservice.rc
|
||||
|
||||
OS_LIBS += $(call EXPAND_LIBNAME,comctl32 ws2_32 shell32)
|
||||
DEFINES += -DUNICODE -D_UNICODE
|
||||
ifndef GNU_CC
|
||||
RCFLAGS += -I$(srcdir)
|
||||
else
|
||||
RCFLAGS += --include-dir $(srcdir)
|
||||
endif
|
||||
|
||||
ifndef MOZ_WINCONSOLE
|
||||
ifdef MOZ_DEBUG
|
||||
MOZ_WINCONSOLE = 1
|
||||
else
|
||||
MOZ_WINCONSOLE = 0
|
||||
endif
|
||||
endif
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
DEFINES += -DNS_NO_XPCOM
|
||||
|
||||
ifdef _MSC_VER
|
||||
WIN32_EXE_LDFLAGS += -ENTRY:wmainCRTStartup
|
||||
endif
|
||||
|
||||
# Pick up nsWindowsRestart.cpp
|
||||
LOCAL_INCLUDES += -I$(topsrcdir)/toolkit/xre \
|
||||
-I$(topsrcdir)/toolkit/mozapps/update/common
|
|
@ -0,0 +1,301 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Maintenance service certificate check code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Brian R. Bondy <netzen@gmail.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <windows.h>
|
||||
#include <softpub.h>
|
||||
#include <wintrust.h>
|
||||
|
||||
#include "certificatecheck.h"
|
||||
#include "servicebase.h"
|
||||
|
||||
#pragma comment(lib, "wintrust.lib")
|
||||
#pragma comment(lib, "crypt32.lib")
|
||||
|
||||
static const int ENCODING = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING;
|
||||
|
||||
/**
|
||||
* Checks to see if a file stored at filePath matches the specified info.
|
||||
*
|
||||
* @param filePath The PE file path to check
|
||||
* @param infoToMatch The acceptable information to match
|
||||
* @return ERROR_SUCCESS if successful, ERROR_NOT_FOUND if the info
|
||||
* does not match, or the last error otherwise.
|
||||
*/
|
||||
DWORD
|
||||
CheckCertificateForPEFile(LPCWSTR filePath,
|
||||
CertificateCheckInfo &infoToMatch)
|
||||
{
|
||||
HCERTSTORE certStore = NULL;
|
||||
HCRYPTMSG cryptMsg = NULL;
|
||||
PCCERT_CONTEXT certContext = NULL;
|
||||
PCMSG_SIGNER_INFO signerInfo = NULL;
|
||||
DWORD lastError = ERROR_SUCCESS;
|
||||
|
||||
// Get the HCERTSTORE and HCRYPTMSG from the signed file.
|
||||
DWORD encoding, contentType, formatType;
|
||||
BOOL result = CryptQueryObject(CERT_QUERY_OBJECT_FILE,
|
||||
filePath,
|
||||
CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED,
|
||||
CERT_QUERY_CONTENT_FLAG_ALL,
|
||||
0, &encoding, &contentType,
|
||||
&formatType, &certStore, &cryptMsg, NULL);
|
||||
if (!result) {
|
||||
lastError = GetLastError();
|
||||
LOG(("CryptQueryObject failed with %d\n", lastError));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
// Pass in NULL to get the needed signer information size.
|
||||
DWORD signerInfoSize;
|
||||
result = CryptMsgGetParam(cryptMsg, CMSG_SIGNER_INFO_PARAM, 0,
|
||||
NULL, &signerInfoSize);
|
||||
if (!result) {
|
||||
lastError = GetLastError();
|
||||
LOG(("CryptMsgGetParam failed with %d\n", lastError));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
// Allocate the needed size for the signer information.
|
||||
signerInfo = (PCMSG_SIGNER_INFO)LocalAlloc(LPTR, signerInfoSize);
|
||||
if (!signerInfo) {
|
||||
lastError = GetLastError();
|
||||
LOG(("Unable to allocate memory for Signer Info.\n"));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
// Get the signer information (PCMSG_SIGNER_INFO).
|
||||
// In particular we want the issuer and serial number.
|
||||
result = CryptMsgGetParam(cryptMsg, CMSG_SIGNER_INFO_PARAM, 0,
|
||||
(PVOID)signerInfo, &signerInfoSize);
|
||||
if (!result) {
|
||||
lastError = GetLastError();
|
||||
LOG(("CryptMsgGetParam failed with %d\n", lastError));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
// Search for the signer certificate in the certificate store.
|
||||
CERT_INFO certInfo;
|
||||
certInfo.Issuer = signerInfo->Issuer;
|
||||
certInfo.SerialNumber = signerInfo->SerialNumber;
|
||||
certContext = CertFindCertificateInStore(certStore, ENCODING, 0,
|
||||
CERT_FIND_SUBJECT_CERT,
|
||||
(PVOID)&certInfo, NULL);
|
||||
if (!certContext) {
|
||||
lastError = GetLastError();
|
||||
LOG(("CertFindCertificateInStore failed with %d\n", lastError));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (!DoCertificateAttributesMatch(certContext, infoToMatch)) {
|
||||
lastError = ERROR_NOT_FOUND;
|
||||
LOG(("Certificate did not match issuer or name\n"));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
if (signerInfo) {
|
||||
LocalFree(signerInfo);
|
||||
}
|
||||
if (certContext) {
|
||||
CertFreeCertificateContext(certContext);
|
||||
}
|
||||
if (certStore) {
|
||||
CertCloseStore(certStore, 0);
|
||||
}
|
||||
if (cryptMsg) {
|
||||
CryptMsgClose(cryptMsg);
|
||||
}
|
||||
return lastError;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to see if a file stored at filePath matches the specified info.
|
||||
*
|
||||
* @param certContext The certificate context of the file
|
||||
* @param infoToMatch The acceptable information to match
|
||||
* @return FALSE if the info does not match or if any error occurs in the check
|
||||
*/
|
||||
BOOL
|
||||
DoCertificateAttributesMatch(PCCERT_CONTEXT certContext,
|
||||
CertificateCheckInfo &infoToMatch)
|
||||
{
|
||||
DWORD dwData;
|
||||
LPTSTR szName = NULL;
|
||||
|
||||
if (infoToMatch.issuer) {
|
||||
// Pass in NULL to get the needed size of the issuer buffer.
|
||||
dwData = CertGetNameString(certContext,
|
||||
CERT_NAME_SIMPLE_DISPLAY_TYPE,
|
||||
CERT_NAME_ISSUER_FLAG, NULL,
|
||||
NULL, 0);
|
||||
|
||||
if (!dwData) {
|
||||
LOG(("CertGetNameString failed.\n"));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Allocate memory for Issuer name buffer.
|
||||
LPTSTR szName = (LPTSTR)LocalAlloc(LPTR, dwData * sizeof(WCHAR));
|
||||
if (!szName) {
|
||||
LOG(("Unable to allocate memory for issuer name.\n"));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Get Issuer name.
|
||||
if (!CertGetNameString(certContext, CERT_NAME_SIMPLE_DISPLAY_TYPE,
|
||||
CERT_NAME_ISSUER_FLAG, NULL, szName, dwData)) {
|
||||
LOG(("CertGetNameString failed.\n"));
|
||||
LocalFree(szName);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// If the issuer does not match, return a failure.
|
||||
if (!infoToMatch.issuer ||
|
||||
wcscmp(szName, infoToMatch.issuer)) {
|
||||
LocalFree(szName);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
LocalFree(szName);
|
||||
szName = NULL;
|
||||
}
|
||||
|
||||
if (infoToMatch.name) {
|
||||
// Pass in NULL to get the needed size of the name buffer.
|
||||
dwData = CertGetNameString(certContext, CERT_NAME_SIMPLE_DISPLAY_TYPE,
|
||||
0, NULL, NULL, 0);
|
||||
if (!dwData) {
|
||||
LOG(("CertGetNameString failed.\n"));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Allocate memory for the name buffer.
|
||||
szName = (LPTSTR)LocalAlloc(LPTR, dwData * sizeof(WCHAR));
|
||||
if (!szName) {
|
||||
LOG(("Unable to allocate memory for subject name.\n"));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Obtain the name.
|
||||
if (!(CertGetNameString(certContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0,
|
||||
NULL, szName, dwData))) {
|
||||
LOG(("CertGetNameString failed.\n"));
|
||||
LocalFree(szName);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// If the issuer does not match, return a failure.
|
||||
if (!infoToMatch.name ||
|
||||
wcscmp(szName, infoToMatch.name)) {
|
||||
LocalFree(szName);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// We have a match!
|
||||
LocalFree(szName);
|
||||
}
|
||||
|
||||
// If there were any errors we would have aborted by now.
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Duplicates the specified string
|
||||
*
|
||||
* @param inputString The string to duplicate
|
||||
* @return The duplicated string which should be freed by the caller.
|
||||
*/
|
||||
LPWSTR
|
||||
AllocateAndCopyWideString(LPCWSTR inputString)
|
||||
{
|
||||
LPWSTR outputString =
|
||||
(LPWSTR)LocalAlloc(LPTR, (wcslen(inputString) + 1) * sizeof(WCHAR));
|
||||
if (outputString) {
|
||||
lstrcpyW(outputString, inputString);
|
||||
}
|
||||
return outputString;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies the trust of the specified file path.
|
||||
*
|
||||
* @param filePath The file path to check.
|
||||
* @return ERROR_SUCCESS if successful, or the last error code otherwise.
|
||||
*/
|
||||
DWORD
|
||||
VerifyCertificateTrustForFile(LPCWSTR filePath)
|
||||
{
|
||||
// Setup the file to check.
|
||||
WINTRUST_FILE_INFO fileToCheck;
|
||||
ZeroMemory(&fileToCheck, sizeof(fileToCheck));
|
||||
fileToCheck.cbStruct = sizeof(WINTRUST_FILE_INFO);
|
||||
fileToCheck.pcwszFilePath = filePath;
|
||||
|
||||
// Setup what to check, we want to check it is signed and trusted.
|
||||
WINTRUST_DATA trustData;
|
||||
ZeroMemory(&trustData, sizeof(trustData));
|
||||
trustData.cbStruct = sizeof(trustData);
|
||||
trustData.pPolicyCallbackData = NULL;
|
||||
trustData.pSIPClientData = NULL;
|
||||
trustData.dwUIChoice = WTD_UI_NONE;
|
||||
trustData.fdwRevocationChecks = WTD_REVOKE_NONE;
|
||||
trustData.dwUnionChoice = WTD_CHOICE_FILE;
|
||||
trustData.dwStateAction = 0;
|
||||
trustData.hWVTStateData = NULL;
|
||||
trustData.pwszURLReference = NULL;
|
||||
// no UI
|
||||
trustData.dwUIContext = 0;
|
||||
trustData.pFile = &fileToCheck;
|
||||
|
||||
GUID policyGUID = WINTRUST_ACTION_GENERIC_VERIFY_V2;
|
||||
// Check if the file is signed by something that is trusted.
|
||||
LONG ret = WinVerifyTrust(NULL, &policyGUID, &trustData);
|
||||
if (ERROR_SUCCESS == ret) {
|
||||
// The hash that represents the subject is trusted and there were no
|
||||
// verification errors. No publisher nor time stamp chain errors.
|
||||
LOG(("The file \"%ls\" is signed and the signature was verified.\n",
|
||||
filePath));
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
DWORD lastError = GetLastError();
|
||||
LOG(("There was an error validating trust of the certificate for file"
|
||||
" \"%ls\". Returned: %d, Last error: %d\n", filePath, ret, lastError));
|
||||
return ret;
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Maintenance service certificate check code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Brian R. Bondy <netzen@gmail.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions /PGM and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _CERTIFICATECHECK_H_
|
||||
#define _CERTIFICATECHECK_H_
|
||||
|
||||
#include <wincrypt.h>
|
||||
|
||||
struct CertificateCheckInfo
|
||||
{
|
||||
LPCWSTR name;
|
||||
LPCWSTR issuer;
|
||||
};
|
||||
|
||||
BOOL DoCertificateAttributesMatch(PCCERT_CONTEXT pCertContext,
|
||||
CertificateCheckInfo &infoToMatch);
|
||||
DWORD VerifyCertificateTrustForFile(LPCWSTR filePath);
|
||||
DWORD CheckCertificateForPEFile(LPCWSTR filePath,
|
||||
CertificateCheckInfo &infoToMatch);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,379 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla Maintenance service.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Brian R. Bondy <netzen@gmail.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include <windows.h>
|
||||
#include <shlwapi.h>
|
||||
#include <stdio.h>
|
||||
#include <wchar.h>
|
||||
|
||||
#include "serviceinstall.h"
|
||||
#include "maintenanceservice.h"
|
||||
#include "servicebase.h"
|
||||
#include "workmonitor.h"
|
||||
#include "shlobj.h"
|
||||
|
||||
SERVICE_STATUS gSvcStatus = { 0 };
|
||||
SERVICE_STATUS_HANDLE gSvcStatusHandle = NULL;
|
||||
HANDLE ghSvcStopEvent = NULL;
|
||||
BOOL gServiceStopping = FALSE;
|
||||
|
||||
// logs are pretty small ~10 lines, so 5 seems reasonable.
|
||||
#define LOGS_TO_KEEP 5
|
||||
|
||||
BOOL GetLogDirectoryPath(WCHAR *path);
|
||||
|
||||
int
|
||||
wmain(int argc, WCHAR **argv)
|
||||
{
|
||||
// If command-line parameter is "install", install the service
|
||||
// or upgrade if already installed
|
||||
// If command line parameter is "forceinstall", install the service
|
||||
// even if it is older than what is already installed.
|
||||
// If command-line parameter is "upgrade", upgrade the service
|
||||
// but do not install it if it is not already installed.
|
||||
// If command line parameter is "uninstall", uninstall the service.
|
||||
// Otherwise, the service is probably being started by the SCM.
|
||||
bool forceInstall = !lstrcmpi(argv[1], L"forceinstall");
|
||||
if (!lstrcmpi(argv[1], L"install") || forceInstall) {
|
||||
WCHAR updatePath[MAX_PATH + 1];
|
||||
if (GetLogDirectoryPath(updatePath)) {
|
||||
LogInit(updatePath, L"maintenanceservice-install.log");
|
||||
}
|
||||
|
||||
LOG(("Installing service"));
|
||||
SvcInstallAction action = InstallSvc;
|
||||
if (forceInstall) {
|
||||
action = ForceInstallSvc;
|
||||
LOG((" with force specified"));
|
||||
}
|
||||
LOG(("...\n"));
|
||||
|
||||
if (!SvcInstall(action)) {
|
||||
LOG(("Could not install service (%d)\n", GetLastError()));
|
||||
LogFinish();
|
||||
return 1;
|
||||
}
|
||||
|
||||
LOG(("The service was installed successfully\n"));
|
||||
LogFinish();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!lstrcmpi(argv[1], L"upgrade")) {
|
||||
WCHAR updatePath[MAX_PATH + 1];
|
||||
if (GetLogDirectoryPath(updatePath)) {
|
||||
LogInit(updatePath, L"maintenanceservice-install.log");
|
||||
}
|
||||
LOG(("Upgrading service if installed...\n"));
|
||||
if (!SvcInstall(UpgradeSvc)) {
|
||||
LOG(("Could not upgrade service (%d)\n", GetLastError()));
|
||||
LogFinish();
|
||||
return 1;
|
||||
}
|
||||
|
||||
LOG(("The service was upgraded successfully\n"));
|
||||
LogFinish();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!lstrcmpi(argv[1], L"uninstall")) {
|
||||
WCHAR updatePath[MAX_PATH + 1];
|
||||
if (GetLogDirectoryPath(updatePath)) {
|
||||
LogInit(updatePath, L"maintenanceservice-uninstall.log");
|
||||
}
|
||||
LOG(("Uninstalling service...\n"));
|
||||
if (!SvcUninstall()) {
|
||||
LOG(("Could not uninstall service (%d)\n", GetLastError()));
|
||||
LogFinish();
|
||||
return 1;
|
||||
}
|
||||
LOG(("The service was uninstalled successfully\n"));
|
||||
LogFinish();
|
||||
return 0;
|
||||
}
|
||||
|
||||
SERVICE_TABLE_ENTRYW DispatchTable[] = {
|
||||
{ SVC_NAME, (LPSERVICE_MAIN_FUNCTION) SvcMain },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
// This call returns when the service has stopped.
|
||||
// The process should simply terminate when the call returns.
|
||||
if (!StartServiceCtrlDispatcher(DispatchTable)) {
|
||||
LOG(("StartServiceCtrlDispatcher failed (%d)\n", GetLastError()));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper callback for the monitoring thread.
|
||||
*
|
||||
* @param param Unused thread callback parameter
|
||||
*/
|
||||
DWORD
|
||||
WINAPI StartMonitoringThreadProc(LPVOID param)
|
||||
{
|
||||
StartDirectoryChangeMonitor();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains the base path where logs should be stored
|
||||
*
|
||||
* @param path The out buffer for the backup log path of size MAX_PATH + 1
|
||||
* @return TRUE if successful.
|
||||
*/
|
||||
BOOL
|
||||
GetLogDirectoryPath(WCHAR *path)
|
||||
{
|
||||
HRESULT hr = SHGetFolderPathW(NULL, CSIDL_COMMON_APPDATA, NULL,
|
||||
SHGFP_TYPE_CURRENT, path);
|
||||
if (FAILED(hr)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!PathAppendSafe(path, L"Mozilla")) {
|
||||
return FALSE;
|
||||
}
|
||||
// The directory should already be created from the installer, but
|
||||
// just to be safe in case someone deletes.
|
||||
CreateDirectoryW(path, NULL);
|
||||
|
||||
if (!PathAppendSafe(path, L"logs")) {
|
||||
return FALSE;
|
||||
}
|
||||
CreateDirectoryW(path, NULL);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculated a backup path based on the log number.
|
||||
*
|
||||
* @param path The out buffer to store the log path of size MAX_PATH + 1
|
||||
* @param basePath The base directory where the calculated path should go
|
||||
* @param logNumber The log number, 0 == updater.log
|
||||
* @return TRUE if successful.
|
||||
*/
|
||||
BOOL
|
||||
GetBackupLogPath(LPWSTR path, LPCWSTR basePath, int logNumber)
|
||||
{
|
||||
WCHAR logName[64];
|
||||
wcscpy(path, basePath);
|
||||
if (logNumber <= 0) {
|
||||
swprintf(logName, L"maintenanceservice.log");
|
||||
} else {
|
||||
swprintf(logName, L"maintenanceservice-%d.log", logNumber);
|
||||
}
|
||||
return PathAppendSafe(path, logName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves the old log files out of the way before a new one is written.
|
||||
* If you for example keep 3 logs, then this function will do:
|
||||
* updater2.log -> updater3.log
|
||||
* updater1.log -> updater2.log
|
||||
* updater.log -> updater1.log
|
||||
* Which clears room for a new updater.log in the basePath directory
|
||||
*
|
||||
* @param basePath The base directory path where log files are stored
|
||||
* @param numLogsToKeep The number of logs to keep
|
||||
*/
|
||||
void
|
||||
BackupOldLogs(LPCWSTR basePath, int numLogsToKeep)
|
||||
{
|
||||
WCHAR oldPath[MAX_PATH + 1];
|
||||
WCHAR newPath[MAX_PATH + 1];
|
||||
for (int i = numLogsToKeep; i >= 1; i--) {
|
||||
if (!GetBackupLogPath(oldPath, basePath, i -1)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!GetBackupLogPath(newPath, basePath, i)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!MoveFileEx(oldPath, newPath, MOVEFILE_REPLACE_EXISTING)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Main entry point when running as a service.
|
||||
*/
|
||||
void WINAPI
|
||||
SvcMain(DWORD dwArgc, LPWSTR *lpszArgv)
|
||||
{
|
||||
// Setup logging, and backup the old logs
|
||||
WCHAR updatePath[MAX_PATH + 1];
|
||||
if (GetLogDirectoryPath(updatePath)) {
|
||||
BackupOldLogs(updatePath, LOGS_TO_KEEP);
|
||||
LogInit(updatePath, L"maintenanceservice.log");
|
||||
}
|
||||
|
||||
// Register the handler function for the service
|
||||
gSvcStatusHandle = RegisterServiceCtrlHandlerW(SVC_NAME, SvcCtrlHandler);
|
||||
if (!gSvcStatusHandle) {
|
||||
LOG(("RegisterServiceCtrlHandler failed (%d)\n", GetLastError()));
|
||||
return;
|
||||
}
|
||||
|
||||
// These SERVICE_STATUS members remain as set here
|
||||
gSvcStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
|
||||
gSvcStatus.dwServiceSpecificExitCode = 0;
|
||||
|
||||
// Report initial status to the SCM
|
||||
ReportSvcStatus(SERVICE_START_PENDING, NO_ERROR, 3000);
|
||||
|
||||
// Perform service-specific initialization and work.
|
||||
SvcInit(dwArgc, lpszArgv);
|
||||
}
|
||||
|
||||
/**
|
||||
* Service initialization.
|
||||
*/
|
||||
void
|
||||
SvcInit(DWORD dwArgc, LPWSTR *lpszArgv)
|
||||
{
|
||||
// Create an event. The control handler function, SvcCtrlHandler,
|
||||
// signals this event when it receives the stop control code.
|
||||
ghSvcStopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
if (NULL == ghSvcStopEvent) {
|
||||
ReportSvcStatus(SERVICE_STOPPED, 1, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
DWORD threadID;
|
||||
HANDLE thread = CreateThread(NULL, 0, StartMonitoringThreadProc, 0,
|
||||
0, &threadID);
|
||||
|
||||
// Report running status when initialization is complete.
|
||||
ReportSvcStatus(SERVICE_RUNNING, NO_ERROR, 0);
|
||||
|
||||
// Perform work until service stops.
|
||||
for(;;) {
|
||||
// Check whether to stop the service.
|
||||
WaitForSingleObject(ghSvcStopEvent, INFINITE);
|
||||
|
||||
WCHAR stopFilePath[MAX_PATH +1];
|
||||
if (!GetUpdateDirectoryPath(stopFilePath)) {
|
||||
LOG(("Could not obtain update directory path, terminating thread "
|
||||
"forcefully.\n"));
|
||||
TerminateThread(thread, 1);
|
||||
}
|
||||
|
||||
// The stop file is to wake up the synchronous call for watching directory
|
||||
// changes. Directory watching will only actually be stopped if
|
||||
// gServiceStopping is also set to TRUE.
|
||||
gServiceStopping = TRUE;
|
||||
if (!PathAppendSafe(stopFilePath, L"stop")) {
|
||||
TerminateThread(thread, 2);
|
||||
}
|
||||
HANDLE stopFile = CreateFile(stopFilePath, GENERIC_READ, 0,
|
||||
NULL, CREATE_ALWAYS, 0, NULL);
|
||||
if (stopFile == INVALID_HANDLE_VALUE) {
|
||||
LOG(("Could not create stop file, terminating thread forcefully.\n"));
|
||||
TerminateThread(thread, 3);
|
||||
} else {
|
||||
CloseHandle(stopFile);
|
||||
DeleteFile(stopFilePath);
|
||||
}
|
||||
|
||||
ReportSvcStatus(SERVICE_STOPPED, NO_ERROR, 0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current service status and reports it to the SCM.
|
||||
*
|
||||
* @param currentState The current state (see SERVICE_STATUS)
|
||||
* @param exitCode The system error code
|
||||
* @param waitHint Estimated time for pending operation in milliseconds
|
||||
*/
|
||||
void
|
||||
ReportSvcStatus(DWORD currentState,
|
||||
DWORD exitCode,
|
||||
DWORD waitHint)
|
||||
{
|
||||
static DWORD dwCheckPoint = 1;
|
||||
|
||||
// Fill in the SERVICE_STATUS structure.
|
||||
gSvcStatus.dwCurrentState = currentState;
|
||||
gSvcStatus.dwWin32ExitCode = exitCode;
|
||||
gSvcStatus.dwWaitHint = waitHint;
|
||||
|
||||
if (SERVICE_START_PENDING == currentState) {
|
||||
gSvcStatus.dwControlsAccepted = 0;
|
||||
} else {
|
||||
gSvcStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
|
||||
}
|
||||
|
||||
if ((SERVICE_RUNNING == currentState) ||
|
||||
(SERVICE_STOPPED == currentState)) {
|
||||
gSvcStatus.dwCheckPoint = 0;
|
||||
} else {
|
||||
gSvcStatus.dwCheckPoint = dwCheckPoint++;
|
||||
}
|
||||
|
||||
// Report the status of the service to the SCM.
|
||||
SetServiceStatus(gSvcStatusHandle, &gSvcStatus);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by SCM whenever a control code is sent to the service
|
||||
* using the ControlService function.
|
||||
*/
|
||||
void WINAPI
|
||||
SvcCtrlHandler(DWORD dwCtrl)
|
||||
{
|
||||
// Handle the requested control code.
|
||||
switch(dwCtrl) {
|
||||
case SERVICE_CONTROL_STOP:
|
||||
ReportSvcStatus(SERVICE_STOP_PENDING, NO_ERROR, 0);
|
||||
// Signal the service to stop.
|
||||
SetEvent(ghSvcStopEvent);
|
||||
ReportSvcStatus(gSvcStatus.dwCurrentState, NO_ERROR, 0);
|
||||
LogFinish();
|
||||
break;
|
||||
case SERVICE_CONTROL_INTERROGATE:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
|
||||
<assemblyIdentity
|
||||
version="1.0.0.0"
|
||||
processorArchitecture="*"
|
||||
name="MaintenanceService"
|
||||
type="win32"
|
||||
/>
|
||||
<description>MaintenanceService</description>
|
||||
<ms_asmv3:trustInfo xmlns:ms_asmv3="urn:schemas-microsoft-com:asm.v3">
|
||||
<ms_asmv3:security>
|
||||
<ms_asmv3:requestedPrivileges>
|
||||
<ms_asmv3:requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
|
||||
</ms_asmv3:requestedPrivileges>
|
||||
</ms_asmv3:security>
|
||||
</ms_asmv3:trustInfo>
|
||||
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
|
||||
<application>
|
||||
<!--The ID below indicates application support for Windows Vista -->
|
||||
<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
|
||||
<!--The ID below indicates application support for Windows 7 -->
|
||||
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
|
||||
</application>
|
||||
</compatibility>
|
||||
</assembly>
|
|
@ -0,0 +1,43 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla Maintenance service.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Brian R. Bondy <netzen@gmail.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
void WINAPI SvcMain(DWORD dwArgc, LPWSTR *lpszArgv);
|
||||
void SvcInit(DWORD dwArgc, LPWSTR *lpszArgv);
|
||||
void WINAPI SvcCtrlHandler(DWORD dwCtrl);
|
||||
void ReportSvcStatus(DWORD dwCurrentState,
|
||||
DWORD dwWin32ExitCode,
|
||||
DWORD dwWaitHint);
|
|
@ -0,0 +1,82 @@
|
|||
// Microsoft Visual C++ generated resource script.
|
||||
//
|
||||
#include "resource.h"
|
||||
|
||||
#define APSTUDIO_READONLY_SYMBOLS
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 2 resource.
|
||||
//
|
||||
#include "winresrc.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#undef APSTUDIO_READONLY_SYMBOLS
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// English (U.S.) resources
|
||||
|
||||
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
|
||||
#ifdef _WIN32
|
||||
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||
#pragma code_page(1252)
|
||||
#endif //_WIN32
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// RT_MANIFEST
|
||||
//
|
||||
|
||||
1 RT_MANIFEST "maintenanceservice.exe.manifest"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// DESIGNINFO
|
||||
//
|
||||
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
GUIDELINES DESIGNINFO
|
||||
BEGIN
|
||||
END
|
||||
#endif // APSTUDIO_INVOKED
|
||||
|
||||
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// TEXTINCLUDE
|
||||
//
|
||||
|
||||
1 TEXTINCLUDE
|
||||
BEGIN
|
||||
"resource.h\0"
|
||||
END
|
||||
|
||||
2 TEXTINCLUDE
|
||||
BEGIN
|
||||
"#include ""winresrc.h""\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
3 TEXTINCLUDE
|
||||
BEGIN
|
||||
"\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
#endif // APSTUDIO_INVOKED
|
||||
|
||||
#endif // English (U.S.) resources
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
#ifndef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 3 resource.
|
||||
//
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#endif // not APSTUDIO_INVOKED
|
||||
|
|
@ -0,0 +1,170 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is for Maintenance service path hashing
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Brian R. Bondy <netzen@gmail.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions /PGM and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include <windows.h>
|
||||
#include <wincrypt.h>
|
||||
#include "pathhash.h"
|
||||
|
||||
|
||||
/**
|
||||
* Converts a binary sequence into a hex string
|
||||
*
|
||||
* @param hash The binary data sequence
|
||||
* @param hashSize The size of the binary data sequence
|
||||
* @param hexString A buffer to store the hex string, must be of
|
||||
* size 2 * @hashSize
|
||||
*/
|
||||
static void
|
||||
BinaryDataToHexString(const BYTE *hash, DWORD &hashSize,
|
||||
LPWSTR hexString)
|
||||
{
|
||||
WCHAR *p = hexString;
|
||||
for (DWORD i = 0; i < hashSize; ++i) {
|
||||
wsprintfW(p, L"%.2x", hash[i]);
|
||||
p += 2;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates an MD5 hash for the given input binary data
|
||||
*
|
||||
* @param data Any sequence of bytes
|
||||
* @param dataSize The number of bytes inside @data
|
||||
* @param hash Output buffer to store hash, must be freed by the caller
|
||||
* @param hashSize The number of bytes in the output buffer
|
||||
* @return TRUE on success
|
||||
*/
|
||||
static BOOL
|
||||
CalculateMD5(const char *data, DWORD dataSize,
|
||||
BYTE **hash, DWORD &hashSize)
|
||||
{
|
||||
HCRYPTPROV hProv = 0;
|
||||
HCRYPTHASH hHash = 0;
|
||||
|
||||
if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, 0)) {
|
||||
if (NTE_BAD_KEYSET != GetLastError()) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Maybe it doesn't exist, try to create it.
|
||||
if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL,
|
||||
CRYPT_NEWKEYSET)) {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (!CryptCreateHash(hProv, CALG_MD5, 0, 0, &hHash)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!CryptHashData(hHash, reinterpret_cast<const BYTE*>(data),
|
||||
dataSize, 0)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
DWORD dwCount = sizeof(DWORD);
|
||||
if (!CryptGetHashParam(hHash, HP_HASHSIZE, (BYTE *)&hashSize,
|
||||
&dwCount, 0)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
*hash = new BYTE[hashSize];
|
||||
ZeroMemory(*hash, hashSize);
|
||||
if (!CryptGetHashParam(hHash, HP_HASHVAL, *hash, &hashSize, 0)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (hHash) {
|
||||
CryptDestroyHash(hHash);
|
||||
}
|
||||
|
||||
if (hProv) {
|
||||
CryptReleaseContext(hProv,0);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a file path into a unique registry location for cert storage
|
||||
*
|
||||
* @param filePath The input file path to get a registry path from
|
||||
* @param registryPath A buffer to write the registry path to, must
|
||||
* be of size in WCHARs MAX_PATH + 1
|
||||
* @return TRUE if successful
|
||||
*/
|
||||
BOOL
|
||||
CalculateRegistryPathFromFilePath(const LPCWSTR filePath,
|
||||
LPWSTR registryPath)
|
||||
{
|
||||
size_t filePathLen = wcslen(filePath);
|
||||
if (!filePathLen) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// If the file path ends in a slash, ignore that character
|
||||
if (filePath[filePathLen -1] == L'\\' ||
|
||||
filePath[filePathLen - 1] == L'/') {
|
||||
filePathLen--;
|
||||
}
|
||||
|
||||
// Copy in the full path into our own buffer.
|
||||
// Copying in the extra slash is OK because we calculate the hash
|
||||
// based on the filePathLen which excludes the slash.
|
||||
// +2 to account for the possibly trailing slash and the null terminator.
|
||||
WCHAR *lowercasePath = new WCHAR[filePathLen + 2];
|
||||
wcscpy(lowercasePath, filePath);
|
||||
_wcslwr(lowercasePath);
|
||||
|
||||
BYTE *hash;
|
||||
DWORD hashSize = 0;
|
||||
if (!CalculateMD5(reinterpret_cast<const char*>(lowercasePath),
|
||||
filePathLen * 2,
|
||||
&hash, hashSize)) {
|
||||
delete[] lowercasePath;
|
||||
return FALSE;
|
||||
}
|
||||
delete[] lowercasePath;
|
||||
|
||||
LPCWSTR baseRegPath = L"SOFTWARE\\Mozilla\\"
|
||||
L"MaintenanceService\\";
|
||||
wcsncpy(registryPath, baseRegPath, MAX_PATH);
|
||||
BinaryDataToHexString(hash, hashSize,
|
||||
registryPath + wcslen(baseRegPath));
|
||||
delete[] hash;
|
||||
return TRUE;
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is for Maintenance service path hashing
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Brian R. Bondy <netzen@gmail.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions /PGM and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _PATHHASH_H_
|
||||
#define _PATHHASH_H_
|
||||
|
||||
/**
|
||||
* Converts a file path into a unique registry location for cert storage
|
||||
*
|
||||
* @param filePath The input file path to get a registry path from
|
||||
* @param registryPath A buffer to write the registry path to, must
|
||||
* be of size in WCHARs MAX_PATH + 1
|
||||
* @return TRUE if successful
|
||||
*/
|
||||
BOOL CalculateRegistryPathFromFilePath(const LPCWSTR filePath,
|
||||
LPWSTR registryPath);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,168 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is for Maintenance service listing allowed certificates
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Brian R. Bondy <netzen@gmail.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <windows.h>
|
||||
|
||||
#include "registrycertificates.h"
|
||||
#include "pathhash.h"
|
||||
#include "nsWindowsHelpers.h"
|
||||
#include "servicebase.h"
|
||||
#define MAX_KEY_LENGTH 255
|
||||
|
||||
/**
|
||||
* Verifies if the file path matches any certificate stored in the registry.
|
||||
*
|
||||
* @param filePath The file path of the application to check if allowed.
|
||||
* @return TRUE if the binary matches any of the allowed certificates.
|
||||
*/
|
||||
BOOL
|
||||
DoesBinaryMatchAllowedCertificates(LPCWSTR basePathForUpdate, LPCWSTR filePath)
|
||||
{
|
||||
WCHAR maintenanceServiceKey[MAX_PATH + 1];
|
||||
if (!CalculateRegistryPathFromFilePath(basePathForUpdate,
|
||||
maintenanceServiceKey)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// We use KEY_WOW64_64KEY to always force 64-bit view.
|
||||
// The user may have both x86 and x64 applications installed
|
||||
// which each register information. We need a consistent place
|
||||
// to put those certificate attributes in and hence why we always
|
||||
// force the non redirected registry under Wow6432Node.
|
||||
// This flag is ignored on 32bit systems.
|
||||
HKEY baseKeyRaw;
|
||||
LSTATUS retCode = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
|
||||
maintenanceServiceKey, 0,
|
||||
KEY_READ | KEY_WOW64_64KEY, &baseKeyRaw);
|
||||
if (retCode != ERROR_SUCCESS) {
|
||||
LOG(("Could not open key. (%d)\n", retCode));
|
||||
// Our tests run with a different apply directory for each test.
|
||||
// We use this registry key on our test slaves to store the
|
||||
// allowed name/issuers.
|
||||
retCode = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
|
||||
L"SOFTWARE\\Mozilla\\MaintenanceService"
|
||||
L"\\3932ecacee736d366d6436db0f55bce4", 0,
|
||||
KEY_READ | KEY_WOW64_64KEY, &baseKeyRaw);
|
||||
if (retCode != ERROR_SUCCESS) {
|
||||
LOG(("Could not open fallback key. (%d)\n", retCode));
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
nsAutoRegKey baseKey(baseKeyRaw);
|
||||
|
||||
// Get the number of subkeys.
|
||||
DWORD subkeyCount = 0;
|
||||
retCode = RegQueryInfoKeyW(baseKey, NULL, NULL, NULL, &subkeyCount, NULL,
|
||||
NULL, NULL, NULL, NULL, NULL, NULL);
|
||||
if (retCode != ERROR_SUCCESS) {
|
||||
LOG(("Could not query info key: %d\n", retCode));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Enumerate the subkeys, each subkey represents an allowed certificate.
|
||||
for (DWORD i = 0; i < subkeyCount; i++) {
|
||||
WCHAR subkeyBuffer[MAX_KEY_LENGTH];
|
||||
DWORD subkeyBufferCount = MAX_KEY_LENGTH;
|
||||
retCode = RegEnumKeyExW(baseKey, i, subkeyBuffer,
|
||||
&subkeyBufferCount, NULL,
|
||||
NULL, NULL, NULL);
|
||||
if (retCode != ERROR_SUCCESS) {
|
||||
LOG(("Could not enum Certs: %d\n", retCode));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Open the subkey for the current certificate
|
||||
HKEY subKeyRaw;
|
||||
retCode = RegOpenKeyExW(baseKey,
|
||||
subkeyBuffer,
|
||||
0,
|
||||
KEY_READ | KEY_WOW64_64KEY,
|
||||
&subKeyRaw);
|
||||
nsAutoRegKey subKey(subKeyRaw);
|
||||
if (retCode != ERROR_SUCCESS) {
|
||||
LOG(("Could not open subkey: %d\n", retCode));
|
||||
continue; // Try the next subkey
|
||||
}
|
||||
|
||||
const int MAX_CHAR_COUNT = 256;
|
||||
DWORD valueBufSize = MAX_CHAR_COUNT * sizeof(WCHAR);
|
||||
WCHAR name[MAX_CHAR_COUNT] = { L'\0' };
|
||||
WCHAR issuer[MAX_CHAR_COUNT] = { L'\0' };
|
||||
|
||||
// Get the name from the registry
|
||||
retCode = RegQueryValueExW(subKey, L"name", 0, NULL,
|
||||
(LPBYTE)name, &valueBufSize);
|
||||
if (retCode != ERROR_SUCCESS) {
|
||||
LOG(("Could not obtain name from registry: %d\n", retCode));
|
||||
continue; // Try the next subkey
|
||||
}
|
||||
|
||||
// Get the issuer from the registry
|
||||
valueBufSize = MAX_CHAR_COUNT * sizeof(WCHAR);
|
||||
retCode = RegQueryValueExW(subKey, L"issuer", 0, NULL,
|
||||
(LPBYTE)issuer, &valueBufSize);
|
||||
if (retCode != ERROR_SUCCESS) {
|
||||
LOG(("Could not obtain issuer from registry: %d\n", retCode));
|
||||
continue; // Try the next subkey
|
||||
}
|
||||
|
||||
CertificateCheckInfo allowedCertificate = {
|
||||
name,
|
||||
issuer,
|
||||
};
|
||||
|
||||
retCode = CheckCertificateForPEFile(filePath, allowedCertificate);
|
||||
if (retCode != ERROR_SUCCESS) {
|
||||
LOG(("Error on certificate check: %d\n", retCode));
|
||||
continue; // Try the next subkey
|
||||
}
|
||||
|
||||
retCode = VerifyCertificateTrustForFile(filePath);
|
||||
if (retCode != ERROR_SUCCESS) {
|
||||
LOG(("Error on certificate trust check: %d\n", retCode));
|
||||
continue; // Try the next subkey
|
||||
}
|
||||
|
||||
// Raise the roof, we found a match!
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// No certificates match, :'(
|
||||
return FALSE;
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is for Maintenance service listing allowed certificates
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Brian R. Bondy <netzen@gmail.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions /PGM and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _REGISTRYCERTIFICATES_H_
|
||||
#define _REGISTRYCERTIFICATES_H_
|
||||
|
||||
#include "certificatecheck.h"
|
||||
|
||||
BOOL DoesBinaryMatchAllowedCertificates(LPCWSTR basePathForUpdate,
|
||||
LPCWSTR filePath);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,16 @@
|
|||
//{{NO_DEPENDENCIES}}
|
||||
// Microsoft Visual C++ generated include file.
|
||||
// Used by updater.rc
|
||||
//
|
||||
#define IDI_DIALOG 1003
|
||||
|
||||
// Next default values for new objects
|
||||
//
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||
#define _APS_NEXT_RESOURCE_VALUE 102
|
||||
#define _APS_NEXT_COMMAND_VALUE 40001
|
||||
#define _APS_NEXT_CONTROL_VALUE 1003
|
||||
#define _APS_NEXT_SYMED_VALUE 101
|
||||
#endif
|
||||
#endif
|
|
@ -0,0 +1,41 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla Maintenance service base code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Brian R. Bondy <netzen@gmail.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "servicebase.h"
|
||||
|
||||
// Shared code between applications and updater.exe
|
||||
#include "nsWindowsRestart.cpp"
|
|
@ -0,0 +1,43 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla Maintenance service base code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Brian R. Bondy <netzen@gmail.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include <windows.h>
|
||||
#include "updatelogging.h"
|
||||
|
||||
BOOL PathAppendSafe(LPWSTR base, LPCWSTR extra);
|
||||
|
||||
#define SERVICE_EVENT_NAME L"Global\\moz-5b780de9-065b-4341-a04f-ddd94b3723e5"
|
|
@ -0,0 +1,416 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Maintenance service service installer code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Brian R. Bondy <netzen@gmail.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include <windows.h>
|
||||
#include <aclapi.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <nsAutoPtr.h>
|
||||
#include <nsWindowsHelpers.h>
|
||||
#include <nsMemory.h>
|
||||
|
||||
#include "serviceinstall.h"
|
||||
#include "servicebase.h"
|
||||
#include "shellapi.h"
|
||||
|
||||
#pragma comment(lib, "version.lib")
|
||||
|
||||
/**
|
||||
* Obtains the version number from the specified PE file's version information
|
||||
* Version Format: A.B.C.D (Example 10.0.0.300)
|
||||
*
|
||||
* @param path The path of the file to check the version on
|
||||
* @param A The first part of the version number
|
||||
* @param B The second part of the version number
|
||||
* @param C The third part of the version number
|
||||
* @param D The fourth part of the version number
|
||||
* @return TRUE if successful
|
||||
*/
|
||||
static BOOL
|
||||
GetVersionNumberFromPath(LPWSTR path, DWORD &A, DWORD &B,
|
||||
DWORD &C, DWORD &D)
|
||||
{
|
||||
DWORD fileVersionInfoSize = GetFileVersionInfoSizeW(path, 0);
|
||||
nsAutoArrayPtr<char> fileVersionInfo = new char[fileVersionInfoSize];
|
||||
if (!GetFileVersionInfoW(path, 0, fileVersionInfoSize,
|
||||
fileVersionInfo.get())) {
|
||||
LOG(("Could not obtain file info of old service. (%d)\n",
|
||||
GetLastError()));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
VS_FIXEDFILEINFO *fixedFileInfo =
|
||||
reinterpret_cast<VS_FIXEDFILEINFO *>(fileVersionInfo.get());
|
||||
UINT size;
|
||||
if (!VerQueryValueW(fileVersionInfo.get(), L"\\",
|
||||
reinterpret_cast<LPVOID*>(&fixedFileInfo), &size)) {
|
||||
LOG(("Could not query file version info of old service. (%d)\n",
|
||||
GetLastError()));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
A = HIWORD(fixedFileInfo->dwFileVersionMS);
|
||||
B = LOWORD(fixedFileInfo->dwFileVersionMS);
|
||||
C = HIWORD(fixedFileInfo->dwFileVersionLS);
|
||||
D = LOWORD(fixedFileInfo->dwFileVersionLS);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Installs or upgrades the MozillaMaintenance service.
|
||||
* If an existing service is already installed, we replace it with the
|
||||
* currently running process.
|
||||
*
|
||||
* @param action The action to perform.
|
||||
* @return TRUE if the service was installed/upgraded
|
||||
*/
|
||||
BOOL
|
||||
SvcInstall(SvcInstallAction action)
|
||||
{
|
||||
// Get a handle to the local computer SCM database with full access rights.
|
||||
nsAutoServiceHandle schSCManager(OpenSCManager(NULL, NULL,
|
||||
SC_MANAGER_ALL_ACCESS));
|
||||
if (!schSCManager) {
|
||||
LOG(("Could not open service manager. (%d)\n", GetLastError()));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
WCHAR newServiceBinaryPath[MAX_PATH + 1];
|
||||
if (!GetModuleFileNameW(NULL, newServiceBinaryPath,
|
||||
sizeof(newServiceBinaryPath) /
|
||||
sizeof(newServiceBinaryPath[0]))) {
|
||||
LOG(("Could not obtain module filename when attempting to "
|
||||
"install service. (%d)\n",
|
||||
GetLastError()));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Check if we already have an open service
|
||||
nsAutoServiceHandle schService(OpenServiceW(schSCManager,
|
||||
SVC_NAME,
|
||||
SERVICE_ALL_ACCESS));
|
||||
DWORD lastError = GetLastError();
|
||||
if (!schService && ERROR_SERVICE_DOES_NOT_EXIST != lastError) {
|
||||
// The service exists but we couldn't open it
|
||||
LOG(("Could not open service. (%d)\n", GetLastError()));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (schService) {
|
||||
// The service exists and we opened it
|
||||
DWORD bytesNeeded;
|
||||
if (!QueryServiceConfigW(schService, NULL, 0, &bytesNeeded) &&
|
||||
GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
|
||||
LOG(("Could not determine buffer size for query service config. (%d)\n",
|
||||
GetLastError()));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Get the service config information, in particular we want the binary
|
||||
// path of the service.
|
||||
nsAutoArrayPtr<char> serviceConfigBuffer = new char[bytesNeeded];
|
||||
if (!QueryServiceConfigW(schService,
|
||||
reinterpret_cast<QUERY_SERVICE_CONFIGW*>(serviceConfigBuffer.get()),
|
||||
bytesNeeded, &bytesNeeded)) {
|
||||
LOG(("Could open service but could not query service config. (%d)\n",
|
||||
GetLastError()));
|
||||
return FALSE;
|
||||
}
|
||||
QUERY_SERVICE_CONFIGW &serviceConfig =
|
||||
*reinterpret_cast<QUERY_SERVICE_CONFIGW*>(serviceConfigBuffer.get());
|
||||
|
||||
// Obtain the existing maintenanceservice file's version number and
|
||||
// the new file's version number. Versions are in the format of
|
||||
// A.B.C.D.
|
||||
DWORD existingA, existingB, existingC, existingD;
|
||||
DWORD newA, newB, newC, newD;
|
||||
BOOL obtainedExistingVersionInfo =
|
||||
GetVersionNumberFromPath(serviceConfig.lpBinaryPathName,
|
||||
existingA, existingB,
|
||||
existingC, existingD);
|
||||
if (!GetVersionNumberFromPath(newServiceBinaryPath, newA,
|
||||
newB, newC, newD)) {
|
||||
LOG(("Could not obtain version number from new path\n"));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
schService.reset(); //Explicitly close the handle so we can delete it
|
||||
|
||||
// Check if we need to replace the old binary with the new one
|
||||
// If we couldn't get the old version info then we assume we should
|
||||
// replace it.
|
||||
if (ForceInstallSvc == action ||
|
||||
!obtainedExistingVersionInfo ||
|
||||
(existingA < newA) ||
|
||||
(existingA == newA && existingB < newB) ||
|
||||
(existingA == newA && existingB == newB &&
|
||||
existingC < newC) ||
|
||||
(existingA == newA && existingB == newB &&
|
||||
existingC == newC && existingD < newD)) {
|
||||
if (!SvcUninstall()) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!DeleteFile(serviceConfig.lpBinaryPathName)) {
|
||||
LOG(("Could not delete old service binary file. (%d)\n", GetLastError()));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!CopyFile(newServiceBinaryPath,
|
||||
serviceConfig.lpBinaryPathName, FALSE)) {
|
||||
LOG(("Could not overwrite old service binary file. "
|
||||
"This should never happen, but if it does the next upgrade will fix"
|
||||
" it, the service is not a critical component that needs to be "
|
||||
" installed for upgrades to work. (%d)\n",
|
||||
GetLastError()));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// We made a copy of ourselves to the existing location.
|
||||
// The tmp file (the process of which we are executing right now) will be
|
||||
// left over. Attempt to delete the file on the next reboot.
|
||||
MoveFileEx(newServiceBinaryPath, NULL, MOVEFILE_DELAY_UNTIL_REBOOT);
|
||||
|
||||
// Setup the new module path
|
||||
wcsncpy(newServiceBinaryPath, serviceConfig.lpBinaryPathName, MAX_PATH);
|
||||
// Fall through so we replace the service
|
||||
} else {
|
||||
// We don't need to copy ourselves to the existing location.
|
||||
// The tmp file (the process of which we are executing right now) will be
|
||||
// left over. Attempt to delete the file on the next reboot.
|
||||
MoveFileEx(newServiceBinaryPath, NULL, MOVEFILE_DELAY_UNTIL_REBOOT);
|
||||
|
||||
return TRUE; // nothing to do, we already have a newer service installed
|
||||
}
|
||||
} else if (UpgradeSvc == action) {
|
||||
// The service does not exist and we are upgrading, so don't install it
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// Create the service as on demand
|
||||
schService.own(CreateServiceW(schSCManager, SVC_NAME, SVC_DISPLAY_NAME,
|
||||
SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS,
|
||||
SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL,
|
||||
newServiceBinaryPath, NULL, NULL, NULL,
|
||||
NULL, NULL));
|
||||
if (!schService) {
|
||||
LOG(("Could not create Windows service. "
|
||||
"This error should never happen since a service install "
|
||||
"should only be called when elevated. (%d)\n", GetLastError()));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!SetUserAccessServiceDACL(schService)) {
|
||||
LOG(("Could not set security ACE on service handle, the service will not be "
|
||||
"able to be started from unelevated processes. "
|
||||
"This error should never happen. (%d)\n",
|
||||
GetLastError()));
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops the Maintenance service.
|
||||
*
|
||||
* @return TRUE if successful.
|
||||
*/
|
||||
BOOL
|
||||
StopService()
|
||||
{
|
||||
// Get a handle to the local computer SCM database with full access rights.
|
||||
nsAutoServiceHandle schSCManager(OpenSCManager(NULL, NULL,
|
||||
SC_MANAGER_ALL_ACCESS));
|
||||
if (!schSCManager) {
|
||||
LOG(("Could not open service manager. (%d)\n", GetLastError()));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Open the service
|
||||
nsAutoServiceHandle schService(OpenServiceW(schSCManager, SVC_NAME,
|
||||
SERVICE_ALL_ACCESS));
|
||||
if (!schService) {
|
||||
LOG(("Could not open service. (%d)\n", GetLastError()));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
SERVICE_STATUS status;
|
||||
return ControlService(schService, SERVICE_CONTROL_STOP, &status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Uninstalls the Maintenance service.
|
||||
*
|
||||
* @return TRUE if successful.
|
||||
*/
|
||||
BOOL
|
||||
SvcUninstall()
|
||||
{
|
||||
// Get a handle to the local computer SCM database with full access rights.
|
||||
nsAutoServiceHandle schSCManager(OpenSCManager(NULL, NULL,
|
||||
SC_MANAGER_ALL_ACCESS));
|
||||
if (!schSCManager) {
|
||||
LOG(("Could not open service manager. (%d)\n", GetLastError()));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Open the service
|
||||
nsAutoServiceHandle schService(OpenServiceW(schSCManager, SVC_NAME,
|
||||
SERVICE_ALL_ACCESS));
|
||||
if (!schService) {
|
||||
LOG(("Could not open service. (%d)\n", GetLastError()));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
//Stop the service so it deletes faster and so the uninstaller
|
||||
// can actually delete its EXE.
|
||||
DWORD totalWaitTime = 0;
|
||||
SERVICE_STATUS status;
|
||||
static const int maxWaitTime = 1000 * 60; // Never wait more than a minute
|
||||
if (ControlService(schService, SERVICE_CONTROL_STOP, &status)) {
|
||||
do {
|
||||
Sleep(status.dwWaitHint);
|
||||
totalWaitTime += (status.dwWaitHint + 10);
|
||||
if (status.dwCurrentState == SERVICE_STOPPED) {
|
||||
break;
|
||||
} else if (totalWaitTime > maxWaitTime) {
|
||||
break;
|
||||
}
|
||||
} while (QueryServiceStatus(schService, &status));
|
||||
}
|
||||
|
||||
// Delete the service or mark it for deletion
|
||||
BOOL deleted = DeleteService(schService);
|
||||
if (!deleted) {
|
||||
deleted = (GetLastError() == ERROR_SERVICE_MARKED_FOR_DELETE);
|
||||
}
|
||||
|
||||
return deleted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the access control list for user access for the specified service.
|
||||
*
|
||||
* @param hService The service to set the access control list on
|
||||
* @return TRUE if successful
|
||||
*/
|
||||
BOOL
|
||||
SetUserAccessServiceDACL(SC_HANDLE hService)
|
||||
{
|
||||
PACL pNewAcl = NULL;
|
||||
PSECURITY_DESCRIPTOR psd = NULL;
|
||||
DWORD lastError = SetUserAccessServiceDACL(hService, pNewAcl, psd);
|
||||
if (pNewAcl) {
|
||||
LocalFree((HLOCAL)pNewAcl);
|
||||
}
|
||||
if (psd) {
|
||||
LocalFree((LPVOID)psd);
|
||||
}
|
||||
return ERROR_SUCCESS == lastError;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the access control list for user access for the specified service.
|
||||
*
|
||||
* @param hService The service to set the access control list on
|
||||
* @param pNewAcl The out param ACL which should be freed by caller
|
||||
* @param psd out param security descriptor, should be freed by caller
|
||||
* @return TRUE if successful
|
||||
*/
|
||||
DWORD
|
||||
SetUserAccessServiceDACL(SC_HANDLE hService, PACL &pNewAcl,
|
||||
PSECURITY_DESCRIPTOR psd)
|
||||
{
|
||||
// Get the current security descriptor needed size
|
||||
DWORD needed = 0;
|
||||
if (!QueryServiceObjectSecurity(hService, DACL_SECURITY_INFORMATION,
|
||||
&psd, 0, &needed)) {
|
||||
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
|
||||
return GetLastError();
|
||||
}
|
||||
|
||||
DWORD size = needed;
|
||||
psd = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR, size);
|
||||
if (!psd) {
|
||||
return ERROR_INSUFFICIENT_BUFFER;
|
||||
}
|
||||
|
||||
// Get the actual security descriptor now
|
||||
if (!QueryServiceObjectSecurity(hService, DACL_SECURITY_INFORMATION,
|
||||
psd, size, &needed)) {
|
||||
return GetLastError();
|
||||
}
|
||||
}
|
||||
|
||||
// Get the current DACL from the security descriptor.
|
||||
PACL pacl = NULL;
|
||||
BOOL bDaclPresent = FALSE;
|
||||
BOOL bDaclDefaulted = FALSE;
|
||||
if ( !GetSecurityDescriptorDacl(psd, &bDaclPresent, &pacl,
|
||||
&bDaclDefaulted)) {
|
||||
return GetLastError();
|
||||
}
|
||||
|
||||
// Build the ACE.
|
||||
EXPLICIT_ACCESS ea;
|
||||
BuildExplicitAccessWithName(&ea, TEXT("Users"),
|
||||
SERVICE_START | SERVICE_STOP | GENERIC_READ,
|
||||
SET_ACCESS, NO_INHERITANCE);
|
||||
DWORD lastError = SetEntriesInAcl(1, (PEXPLICIT_ACCESS)&ea, pacl, &pNewAcl);
|
||||
if (ERROR_SUCCESS != lastError) {
|
||||
return lastError;
|
||||
}
|
||||
|
||||
// Initialize a new security descriptor.
|
||||
SECURITY_DESCRIPTOR sd;
|
||||
if (!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION)) {
|
||||
return GetLastError();
|
||||
}
|
||||
|
||||
// Set the new DACL in the security descriptor.
|
||||
if (!SetSecurityDescriptorDacl(&sd, TRUE, pNewAcl, FALSE)) {
|
||||
return GetLastError();
|
||||
}
|
||||
|
||||
// Set the new security descriptor for the service object.
|
||||
if (!SetServiceObjectSecurity(hService, DACL_SECURITY_INFORMATION, &sd)) {
|
||||
return GetLastError();
|
||||
}
|
||||
|
||||
// Woohoo, raise the roof
|
||||
return ERROR_SUCCESS;
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Maintenance service service installer code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Brian R. Bondy <netzen@gmail.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#define SVC_NAME L"MozillaMaintenance"
|
||||
#define SVC_DISPLAY_NAME L"Mozilla Maintenance Service"
|
||||
|
||||
enum SvcInstallAction { UpgradeSvc, InstallSvc, ForceInstallSvc };
|
||||
BOOL SvcInstall(SvcInstallAction action);
|
||||
BOOL SvcUninstall();
|
||||
BOOL StopService();
|
||||
BOOL SetUserAccessServiceDACL(SC_HANDLE hService);
|
||||
DWORD SetUserAccessServiceDACL(SC_HANDLE hService, PACL &pNewAcl,
|
||||
PSECURITY_DESCRIPTOR psd);
|
|
@ -0,0 +1,647 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Maintenance service file system monitoring.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Brian R. Bondy <netzen@gmail.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include <shlobj.h>
|
||||
#include <shlwapi.h>
|
||||
#include <wtsapi32.h>
|
||||
#include <userenv.h>
|
||||
#include <shellapi.h>
|
||||
|
||||
#pragma comment(lib, "wtsapi32.lib")
|
||||
#pragma comment(lib, "userenv.lib")
|
||||
#pragma comment(lib, "shlwapi.lib")
|
||||
|
||||
#include "nsWindowsHelpers.h"
|
||||
#include "nsAutoPtr.h"
|
||||
|
||||
#include "workmonitor.h"
|
||||
#include "serviceinstall.h"
|
||||
#include "servicebase.h"
|
||||
#include "registrycertificates.h"
|
||||
#include "uachelper.h"
|
||||
#include "launchwinprocess.h"
|
||||
|
||||
extern BOOL gServiceStopping;
|
||||
|
||||
// Wait 15 minutes for an update operation to run at most.
|
||||
// Updates usually take less than a minute so this seems like a
|
||||
// significantly large and safe amount of time to wait.
|
||||
static const int TIME_TO_WAIT_ON_UPDATER = 15 * 60 * 1000;
|
||||
PRUnichar* MakeCommandLine(int argc, PRUnichar **argv);
|
||||
BOOL WriteStatusFailure(LPCWSTR updateDirPath, int errorCode);
|
||||
BOOL WriteStatusPending(LPCWSTR updateDirPath);
|
||||
BOOL StartCallbackApp(int argcTmp, LPWSTR *argvTmp, DWORD callbackSessionID);
|
||||
BOOL PathGetSiblingFilePath(LPWSTR destinationBuffer, LPCWSTR siblingFilePath,
|
||||
LPCWSTR newFileName);
|
||||
|
||||
// The error codes start from 16000 since Windows system error
|
||||
// codes only go up to 15999
|
||||
const int SERVICE_UPDATER_COULD_NOT_BE_STARTED = 16000;
|
||||
const int SERVICE_NOT_ENOUGH_COMMAND_LINE_ARGS = 16001;
|
||||
const int SERVICE_UPDATER_SIGN_ERROR = 16002;
|
||||
const int SERVICE_CALLBACK_SIGN_ERROR = 16003;
|
||||
|
||||
/**
|
||||
* Runs an update process in the specified sessionID as an elevated process.
|
||||
*
|
||||
* @param updaterPath The path to the update process to start.
|
||||
* @param workingDir The working directory to execute the update process
|
||||
* @param cmdLine in. The command line parameters to pass to the update
|
||||
* process. If they specify a callback application, it
|
||||
* will be executed with an associated unelevated token
|
||||
* for the sessionID.
|
||||
* @param processStarted Returns TRUE if the process was started.
|
||||
* @param callbackSessionID
|
||||
* If 0 and Windows Vista, the callback application will
|
||||
* not be run. If non zero the callback application will
|
||||
* be injected into the user's session as a non-elevated
|
||||
* process.
|
||||
* @return TRUE if the update process was run had a return code of 0.
|
||||
*/
|
||||
BOOL
|
||||
StartUpdateProcess(LPCWSTR updaterPath,
|
||||
LPCWSTR workingDir,
|
||||
int argcTmp,
|
||||
LPWSTR *argvTmp,
|
||||
BOOL &processStarted,
|
||||
DWORD callbackSessionID = 0)
|
||||
{
|
||||
DWORD myProcessID = GetCurrentProcessId();
|
||||
DWORD mySessionID = 0;
|
||||
ProcessIdToSessionId(myProcessID, &mySessionID);
|
||||
|
||||
STARTUPINFO si = {0};
|
||||
si.cb = sizeof(STARTUPINFO);
|
||||
si.lpDesktop = L"winsta0\\Default";
|
||||
PROCESS_INFORMATION pi = {0};
|
||||
|
||||
LOG(("Starting process in an elevated session. Service "
|
||||
"session ID: %d; Requested callback session ID: %d\n",
|
||||
mySessionID, callbackSessionID));
|
||||
|
||||
// The updater command line is of the form:
|
||||
// updater.exe update-dir apply [wait-pid [callback-dir callback-path args]]
|
||||
// So update callback-dir is the 4th, callback-path is the 5th and its args
|
||||
// are the 6th index. So that we can execute the callback out of line we
|
||||
// won't call updater.exe with those callback args and we will manage the
|
||||
// callback ourselves.
|
||||
LPWSTR cmdLine = MakeCommandLine(argcTmp, argvTmp);
|
||||
|
||||
// If we're about to start the update process from session 0,
|
||||
// then we should not show a GUI. This only really needs to be done
|
||||
// on Vista and higher, but it's better to keep everything consistent
|
||||
// across all OS if it's of no harm.
|
||||
if (argcTmp >= 2 ) {
|
||||
// Setting the desktop to blank will ensure no GUI is displayed
|
||||
si.lpDesktop = L"";
|
||||
si.dwFlags |= STARTF_USESHOWWINDOW;
|
||||
si.wShowWindow = SW_HIDE;
|
||||
}
|
||||
|
||||
// We move the updater.ini file out of the way because we will handle
|
||||
// executing PostUpdate through the service. We handle PostUpdate from
|
||||
// the service because there are some per user things that happen that
|
||||
// can't run in session 0 which we run updater.exe in.
|
||||
// Once we are done running updater.exe we rename updater.ini back so
|
||||
// that if there were any errors the next updater.exe will run correctly.
|
||||
WCHAR updaterINI[MAX_PATH + 1];
|
||||
WCHAR updaterINITemp[MAX_PATH + 1];
|
||||
BOOL selfHandlePostUpdate = FALSE;
|
||||
// We use the updater.ini from the same directory as the updater.exe
|
||||
// because of background updates.
|
||||
if (PathGetSiblingFilePath(updaterINI, argvTmp[0], L"updater.ini") &&
|
||||
PathGetSiblingFilePath(updaterINITemp, argvTmp[0], L"updater.tmp")) {
|
||||
selfHandlePostUpdate = MoveFileEx(updaterINI, updaterINITemp,
|
||||
MOVEFILE_REPLACE_EXISTING);
|
||||
}
|
||||
|
||||
// Create an environment block for the process we're about to start using
|
||||
// the user's token.
|
||||
WCHAR envVarString[32];
|
||||
wsprintf(envVarString, L"MOZ_SESSION_ID=%d", callbackSessionID);
|
||||
_wputenv(envVarString);
|
||||
LPVOID environmentBlock = NULL;
|
||||
if (!CreateEnvironmentBlock(&environmentBlock, NULL, TRUE)) {
|
||||
LOG(("Could not create an environment block, setting it to NULL.\n"));
|
||||
environmentBlock = NULL;
|
||||
}
|
||||
// Empty value on _wputenv is how you remove an env variable in Windows
|
||||
_wputenv(L"MOZ_SESSION_ID=");
|
||||
processStarted = CreateProcessW(updaterPath, cmdLine,
|
||||
NULL, NULL, FALSE,
|
||||
CREATE_DEFAULT_ERROR_MODE |
|
||||
CREATE_UNICODE_ENVIRONMENT,
|
||||
environmentBlock,
|
||||
workingDir, &si, &pi);
|
||||
if (environmentBlock) {
|
||||
DestroyEnvironmentBlock(environmentBlock);
|
||||
}
|
||||
BOOL updateWasSuccessful = FALSE;
|
||||
if (processStarted) {
|
||||
// Wait for the updater process to finish
|
||||
LOG(("Process was started... waiting on result.\n"));
|
||||
DWORD waitRes = WaitForSingleObject(pi.hProcess, TIME_TO_WAIT_ON_UPDATER);
|
||||
if (WAIT_TIMEOUT == waitRes) {
|
||||
// We waited a long period of time for updater.exe and it never finished
|
||||
// so kill it.
|
||||
TerminateProcess(pi.hProcess, 1);
|
||||
} else {
|
||||
// Check the return code of updater.exe to make sure we get 0
|
||||
DWORD returnCode;
|
||||
if (GetExitCodeProcess(pi.hProcess, &returnCode)) {
|
||||
LOG(("Process finished with return code %d.\n", returnCode));
|
||||
// updater returns 0 if successful.
|
||||
updateWasSuccessful = (returnCode == 0);
|
||||
} else {
|
||||
LOG(("Process finished but could not obtain return code.\n"));
|
||||
}
|
||||
}
|
||||
CloseHandle(pi.hProcess);
|
||||
CloseHandle(pi.hThread);
|
||||
} else {
|
||||
DWORD lastError = GetLastError();
|
||||
LOG(("Could not create process as current user, "
|
||||
"updaterPath: %ls; cmdLine: %l. (%d)\n",
|
||||
updaterPath, cmdLine, lastError));
|
||||
}
|
||||
|
||||
// Now that we're done with the update, restore back the updater.ini file
|
||||
// We use it ourselves, and also we want it back in case we had any type
|
||||
// of error so that the normal update process can use it.
|
||||
if (selfHandlePostUpdate) {
|
||||
MoveFileEx(updaterINITemp, updaterINI, MOVEFILE_REPLACE_EXISTING);
|
||||
|
||||
// Only run the PostUpdate if the update was successful and if we have
|
||||
// a callback application. This is the same thing updater.exe does.
|
||||
if (updateWasSuccessful && argcTmp > 5) {
|
||||
LPCWSTR callbackApplication = argvTmp[5];
|
||||
LPCWSTR updateInfoDir = argvTmp[1];
|
||||
// Launch the PostUpdate process with SYSTEM in session 0. We force sync
|
||||
// because we run this twice and we want to make sure the uninstaller
|
||||
// keys get added to HKLM before the ones try to get added to HKCU. If
|
||||
// we did it async we'd have a race condition that would sometimes lead
|
||||
// to 2 uninstall icons.
|
||||
LaunchWinPostProcess(callbackApplication, updateInfoDir, true, NULL);
|
||||
nsAutoHandle userToken(UACHelper::OpenUserToken(callbackSessionID));
|
||||
LaunchWinPostProcess(callbackApplication,
|
||||
updateInfoDir, false, userToken);
|
||||
}
|
||||
}
|
||||
|
||||
free(cmdLine);
|
||||
return updateWasSuccessful;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes a work item (file by the name of .mz) and executes
|
||||
* the command within.
|
||||
* The only supported command at this time is running an update.
|
||||
*
|
||||
* @param monitoringBasePath The base path that is being monitored.
|
||||
* @param notifyInfo the notifyInfo struct for the changes.
|
||||
* @return TRUE if we want the service to stop.
|
||||
*/
|
||||
BOOL
|
||||
ProcessWorkItem(LPCWSTR monitoringBasePath,
|
||||
FILE_NOTIFY_INFORMATION ¬ifyInfo)
|
||||
{
|
||||
int filenameLength = notifyInfo.FileNameLength /
|
||||
sizeof(notifyInfo.FileName[0]);
|
||||
notifyInfo.FileName[filenameLength] = L'\0';
|
||||
|
||||
// When the file is ready for processing it will be renamed
|
||||
// to have a .mz extension
|
||||
BOOL haveWorkItem = notifyInfo.Action == FILE_ACTION_RENAMED_NEW_NAME &&
|
||||
notifyInfo.FileNameLength > 3 &&
|
||||
notifyInfo.FileName[filenameLength - 3] == L'.' &&
|
||||
notifyInfo.FileName[filenameLength - 2] == L'm' &&
|
||||
notifyInfo.FileName[filenameLength - 1] == L'z';
|
||||
if (!haveWorkItem) {
|
||||
// We don't have a work item, keep looking
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Indicate that the service is busy and shouldn't be used by anyone else
|
||||
// by creating a named event. Programs should check if this event exists
|
||||
// before writing a work item out.
|
||||
nsAutoHandle serviceRunning(CreateEventW(NULL, TRUE,
|
||||
FALSE, SERVICE_EVENT_NAME));
|
||||
|
||||
LOG(("Processing new command meta file: %ls\n", notifyInfo.FileName));
|
||||
WCHAR fullMetaUpdateFilePath[MAX_PATH + 1];
|
||||
wcscpy(fullMetaUpdateFilePath, monitoringBasePath);
|
||||
|
||||
// We only support file paths in monitoring directories that are MAX_PATH
|
||||
// chars or less.
|
||||
if (!PathAppendSafe(fullMetaUpdateFilePath, notifyInfo.FileName)) {
|
||||
// Cannot process update, skipfileSize it.
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
nsAutoHandle metaUpdateFile(CreateFile(fullMetaUpdateFilePath,
|
||||
GENERIC_READ,
|
||||
FILE_SHARE_READ |
|
||||
FILE_SHARE_WRITE |
|
||||
FILE_SHARE_DELETE,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
0, NULL));
|
||||
if (metaUpdateFile == INVALID_HANDLE_VALUE) {
|
||||
LOG(("Could not open command meta file: %ls\n", notifyInfo.FileName));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
DWORD fileSize = GetFileSize(metaUpdateFile, NULL);
|
||||
DWORD sessionID = 0, commandID = 0;
|
||||
// The file should be in wide characters so if it's of odd size it's
|
||||
// an invalid file.
|
||||
const int kSanityCheckFileSize = 1024 * 64;
|
||||
if (fileSize == INVALID_FILE_SIZE ||
|
||||
(fileSize %2) != 0 ||
|
||||
fileSize > kSanityCheckFileSize ||
|
||||
fileSize < sizeof(DWORD)) {
|
||||
LOG(("Could not obtain file size or an improper file size was encountered "
|
||||
"for command meta file: %ls\n",
|
||||
notifyInfo.FileName));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// The first 4 bytes are for the command ID.
|
||||
// Currently only command ID 1 which is for updates is supported.
|
||||
DWORD commandIDCount;
|
||||
BOOL result = ReadFile(metaUpdateFile, &commandID,
|
||||
sizeof(DWORD), &commandIDCount, NULL);
|
||||
fileSize -= sizeof(DWORD);
|
||||
|
||||
// The next 4 bytes are for the process ID
|
||||
DWORD sessionIDCount;
|
||||
result |= ReadFile(metaUpdateFile, &sessionID,
|
||||
sizeof(DWORD), &sessionIDCount, NULL);
|
||||
fileSize -= sizeof(DWORD);
|
||||
|
||||
// The next MAX_PATH wchar's are for the app to start
|
||||
WCHAR updaterPath[MAX_PATH + 1];
|
||||
ZeroMemory(updaterPath, sizeof(updaterPath));
|
||||
DWORD updaterPathCount;
|
||||
result |= ReadFile(metaUpdateFile, updaterPath,
|
||||
MAX_PATH * sizeof(WCHAR), &updaterPathCount, NULL);
|
||||
fileSize -= updaterPathCount;
|
||||
|
||||
// The next MAX_PATH wchar's are for the app to start
|
||||
WCHAR workingDirectory[MAX_PATH + 1];
|
||||
ZeroMemory(workingDirectory, sizeof(workingDirectory));
|
||||
DWORD workingDirectoryCount;
|
||||
result |= ReadFile(metaUpdateFile, workingDirectory,
|
||||
MAX_PATH * sizeof(WCHAR), &workingDirectoryCount, NULL);
|
||||
fileSize -= workingDirectoryCount;
|
||||
|
||||
// + 2 for wide char termination
|
||||
nsAutoArrayPtr<char> cmdlineBuffer = new char[fileSize + 2];
|
||||
DWORD cmdLineBufferRead;
|
||||
result |= ReadFile(metaUpdateFile, cmdlineBuffer,
|
||||
fileSize, &cmdLineBufferRead, NULL);
|
||||
fileSize -= cmdLineBufferRead;
|
||||
|
||||
// We have all the info we need from the work item file, get rid of it.
|
||||
metaUpdateFile.reset();
|
||||
if (!DeleteFileW(fullMetaUpdateFilePath)) {
|
||||
LOG(("Could not delete work item file: %ls. (%d)\n",
|
||||
fullMetaUpdateFilePath, GetLastError()));
|
||||
}
|
||||
|
||||
if (!result ||
|
||||
commandID != 1 ||
|
||||
commandIDCount != sizeof(DWORD) ||
|
||||
sessionIDCount != sizeof(DWORD) ||
|
||||
updaterPathCount != MAX_PATH * sizeof(WCHAR) ||
|
||||
workingDirectoryCount != MAX_PATH * sizeof(WCHAR) ||
|
||||
fileSize != 0) {
|
||||
LOG(("Could not read command data for command meta file: %ls\n",
|
||||
notifyInfo.FileName));
|
||||
return TRUE;
|
||||
}
|
||||
cmdlineBuffer[cmdLineBufferRead] = '\0';
|
||||
cmdlineBuffer[cmdLineBufferRead + 1] = '\0';
|
||||
WCHAR *cmdlineBufferWide = reinterpret_cast<WCHAR*>(cmdlineBuffer.get());
|
||||
LOG(("An update command was detected and is being processed for command meta "
|
||||
"file: %ls\n",
|
||||
notifyInfo.FileName));
|
||||
|
||||
int argcTmp = 0;
|
||||
LPWSTR* argvTmp = CommandLineToArgvW(cmdlineBufferWide, &argcTmp);
|
||||
|
||||
// Check for callback application sign problems
|
||||
BOOL callbackSignProblem = FALSE;
|
||||
#ifndef DISABLE_CALLBACK_AUTHENTICODE_CHECK
|
||||
// If we have less than 6 params, then there is no callback to check, so
|
||||
// we have no callback sign problem.
|
||||
if (argcTmp > 5) {
|
||||
LPWSTR callbackApplication = argvTmp[5];
|
||||
callbackSignProblem =
|
||||
!DoesBinaryMatchAllowedCertificates(argvTmp[2], callbackApplication);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Check for updater.exe sign problems
|
||||
BOOL updaterSignProblem = FALSE;
|
||||
#ifndef DISABLE_SERVICE_AUTHENTICODE_CHECK
|
||||
if (argcTmp > 2) {
|
||||
updaterSignProblem = !DoesBinaryMatchAllowedCertificates(argvTmp[2],
|
||||
updaterPath);
|
||||
}
|
||||
#endif
|
||||
|
||||
// In order to proceed with the update we need at least 3 command line
|
||||
// parameters and no sign problems.
|
||||
if (argcTmp > 2 && !updaterSignProblem && !callbackSignProblem) {
|
||||
BOOL updateProcessWasStarted = FALSE;
|
||||
if (StartUpdateProcess(updaterPath, workingDirectory,
|
||||
argcTmp, argvTmp,
|
||||
updateProcessWasStarted,
|
||||
sessionID)) {
|
||||
LOG(("updater.exe was launched and run successfully!\n"));
|
||||
StartServiceUpdate(argcTmp, argvTmp);
|
||||
} else {
|
||||
LOG(("Error running process in session %d. "
|
||||
"Updating update.status. Last error: %d\n",
|
||||
sessionID, GetLastError()));
|
||||
|
||||
// If the update process was started, then updater.exe is responsible for
|
||||
// setting the failure code and running the callback. If it could not
|
||||
// be started then we do the work. We set an error instead of directly
|
||||
// setting status pending so that the app.update.service.errors
|
||||
// pref can be updated when the callback app restarts.
|
||||
if (!updateProcessWasStarted) {
|
||||
if (!WriteStatusFailure(argvTmp[1],
|
||||
SERVICE_UPDATER_COULD_NOT_BE_STARTED)) {
|
||||
LOG(("Could not write update.status service update failure."
|
||||
"Last error: %d\n", GetLastError()));
|
||||
}
|
||||
|
||||
// We only hit this condition when there is no callback sign error
|
||||
// so we don't need to check it.
|
||||
StartCallbackApp(argcTmp, argvTmp, sessionID);
|
||||
}
|
||||
}
|
||||
} else if (argcTmp <= 2) {
|
||||
LOG(("Not enough command line parameters specified. "
|
||||
"Updating update.status.\n"));
|
||||
|
||||
// We can't start the callback in this case because there
|
||||
// are not enough command line parameters. We set an error instead of
|
||||
// directly setting status pending so that the app.update.service.errors
|
||||
// pref can be updated when the callback app restarts.
|
||||
if (argcTmp != 2 ||
|
||||
!WriteStatusFailure(argvTmp[1],
|
||||
SERVICE_NOT_ENOUGH_COMMAND_LINE_ARGS)) {
|
||||
LOG(("Could not write update.status service update failure."
|
||||
"Last error: %d\n", GetLastError()));
|
||||
}
|
||||
} else if (callbackSignProblem) {
|
||||
LOG(("Will not run updater nor callback due to callback sign error "
|
||||
"in session %d. Updating update.status. Last error: %d\n",
|
||||
sessionID, GetLastError()));
|
||||
|
||||
// When there is a certificate check error on the callback application, we
|
||||
// want to write out the error.
|
||||
if (!WriteStatusFailure(argvTmp[1],
|
||||
SERVICE_CALLBACK_SIGN_ERROR)) {
|
||||
LOG(("Could not write pending state to update.status. (%d)\n",
|
||||
GetLastError()));
|
||||
}
|
||||
} else {
|
||||
LOG(("Could not start process due to certificate check error on "
|
||||
"updater.exe. Updating update.status. Last error: %d\n", GetLastError()));
|
||||
|
||||
// When there is a certificate check error on the updater.exe application,
|
||||
// we want to write out the error.
|
||||
if (!WriteStatusFailure(argvTmp[1],
|
||||
SERVICE_UPDATER_SIGN_ERROR)) {
|
||||
LOG(("Could not write pending state to update.status. (%d)\n",
|
||||
GetLastError()));
|
||||
}
|
||||
|
||||
// On certificate check errors on updater.exe, updater.exe won't run at all
|
||||
// so we need to manually start the callback application ourselves.
|
||||
// This condition will only be hit when the callback app has no sign errors
|
||||
StartCallbackApp(argcTmp, argvTmp, sessionID);
|
||||
}
|
||||
LocalFree(argvTmp);
|
||||
|
||||
// We processed a work item, whether or not it was successful.
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts monitoring the update directory for work items.
|
||||
*
|
||||
* @return FALSE if there was an error starting directory monitoring.
|
||||
*/
|
||||
BOOL
|
||||
StartDirectoryChangeMonitor()
|
||||
{
|
||||
LOG(("Starting directory change monitor...\n"));
|
||||
|
||||
// Init the update directory path and ensure it exists.
|
||||
// Example: C:\programData\Mozilla\Firefox\updates\[channel]
|
||||
// The channel is not included here as we want to monitor the base directory
|
||||
WCHAR updateData[MAX_PATH + 1];
|
||||
if (!GetUpdateDirectoryPath(updateData)) {
|
||||
LOG(("Could not obtain update directory path\n"));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Obtain a directory handle, FILE_FLAG_BACKUP_SEMANTICS is needed for this.
|
||||
nsAutoHandle directoryHandle(CreateFile(updateData,
|
||||
FILE_LIST_DIRECTORY,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
FILE_FLAG_BACKUP_SEMANTICS,
|
||||
NULL));
|
||||
if (directoryHandle == INVALID_HANDLE_VALUE) {
|
||||
LOG(("Could not obtain directory handle to monitor\n"));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Allocate a buffer that is big enough to hold 128 changes
|
||||
// Note that FILE_NOTIFY_INFORMATION is a variable length struct
|
||||
// so that's why we don't create a simple array directly.
|
||||
char fileNotifyInfoBuffer[(sizeof(FILE_NOTIFY_INFORMATION) +
|
||||
MAX_PATH) * 128];
|
||||
ZeroMemory(&fileNotifyInfoBuffer, sizeof(fileNotifyInfoBuffer));
|
||||
|
||||
DWORD bytesReturned;
|
||||
// Listen for directory changes to the update directory
|
||||
while (ReadDirectoryChangesW(directoryHandle,
|
||||
fileNotifyInfoBuffer,
|
||||
sizeof(fileNotifyInfoBuffer),
|
||||
TRUE, FILE_NOTIFY_CHANGE_FILE_NAME,
|
||||
&bytesReturned, NULL, NULL)) {
|
||||
char *fileNotifyInfoBufferLocation = fileNotifyInfoBuffer;
|
||||
|
||||
// Make sure we have at least one entry to process
|
||||
while (bytesReturned/sizeof(FILE_NOTIFY_INFORMATION) > 0) {
|
||||
// Point to the current directory info which is changed
|
||||
FILE_NOTIFY_INFORMATION ¬ifyInfo =
|
||||
*((FILE_NOTIFY_INFORMATION*)fileNotifyInfoBufferLocation);
|
||||
fileNotifyInfoBufferLocation += notifyInfo .NextEntryOffset;
|
||||
bytesReturned -= notifyInfo .NextEntryOffset;
|
||||
if (!wcscmp(notifyInfo.FileName, L"stop") && gServiceStopping) {
|
||||
LOG(("A stop command was issued.\n"));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL processedWorkItem = ProcessWorkItem(updateData, notifyInfo);
|
||||
if (processedWorkItem) {
|
||||
// We don't return here because during stop we will write out a stop
|
||||
// file which will stop monitoring.
|
||||
StopService();
|
||||
break;
|
||||
}
|
||||
|
||||
// NextEntryOffset will be 0 if there are no more items to monitor,
|
||||
// and we're ready to make another call to ReadDirectoryChangesW.
|
||||
if (0 == notifyInfo.NextEntryOffset) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the callback application from the updater.exe command line arguments.
|
||||
*
|
||||
* @param argcTmp The argc value normally sent to updater.exe
|
||||
* @param argvTmp The argv value normally sent to updater.exe
|
||||
* @param callbackSessionID The session ID to start the callback with
|
||||
* @return TRUE if successful
|
||||
*/
|
||||
BOOL
|
||||
StartCallbackApp(int argcTmp, LPWSTR *argvTmp, DWORD callbackSessionID)
|
||||
{
|
||||
if (0 == callbackSessionID && UACHelper::IsVistaOrLater()) {
|
||||
LOG(("Attempted to run callback application in session 0, not allowed.\n"));
|
||||
LOG(("Session 0 is only for services on Vista and up.\n"));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (argcTmp < 5) {
|
||||
LOG(("No callback application specified.\n"));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
LPWSTR callbackArgs = NULL;
|
||||
LPWSTR callbackDirectory = argvTmp[4];
|
||||
LPWSTR callbackApplication = argvTmp[5];
|
||||
if (argcTmp > 6) {
|
||||
// Make room for all of the ending args minus the first 6
|
||||
// + 1 for the app itself
|
||||
const size_t callbackCommandLineLen = argcTmp - 5;
|
||||
WCHAR **params = new WCHAR*[callbackCommandLineLen];
|
||||
params[0] = callbackApplication;
|
||||
for (size_t i = 1; i < callbackCommandLineLen; ++i) {
|
||||
params[i] = argvTmp[5 + i];
|
||||
}
|
||||
callbackArgs = MakeCommandLine(callbackCommandLineLen, params);
|
||||
delete[] params;
|
||||
}
|
||||
|
||||
if (!callbackApplication) {
|
||||
LOG(("Callback application is NULL.\n"));
|
||||
if (callbackArgs) {
|
||||
free(callbackArgs);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
nsAutoHandle unelevatedToken(UACHelper::OpenUserToken(callbackSessionID));
|
||||
if (!unelevatedToken) {
|
||||
LOG(("Could not obtain unelevated token for callback app.\n"));
|
||||
if (callbackArgs) {
|
||||
free(callbackArgs);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Create an environment block for the process we're about to start using
|
||||
// the user's token.
|
||||
LPVOID environmentBlock = NULL;
|
||||
if (!CreateEnvironmentBlock(&environmentBlock, unelevatedToken, TRUE)) {
|
||||
LOG(("Could not create an environment block, setting it to NULL.\n"));
|
||||
environmentBlock = NULL;
|
||||
}
|
||||
|
||||
STARTUPINFOW si = {0};
|
||||
si.cb = sizeof(STARTUPINFOW);
|
||||
si.lpDesktop = L"winsta0\\Default";
|
||||
PROCESS_INFORMATION pi = {0};
|
||||
if (CreateProcessAsUserW(unelevatedToken,
|
||||
callbackApplication,
|
||||
callbackArgs,
|
||||
NULL, NULL, FALSE,
|
||||
CREATE_DEFAULT_ERROR_MODE |
|
||||
#ifdef DEBUG
|
||||
CREATE_NEW_CONSOLE |
|
||||
#endif
|
||||
CREATE_UNICODE_ENVIRONMENT,
|
||||
environmentBlock,
|
||||
callbackDirectory,
|
||||
&si, &pi)) {
|
||||
LOG(("Callback app was run successfully.\n"));
|
||||
CloseHandle(pi.hProcess);
|
||||
CloseHandle(pi.hThread);
|
||||
if (environmentBlock) {
|
||||
DestroyEnvironmentBlock(environmentBlock);
|
||||
}
|
||||
if (callbackArgs) {
|
||||
free(callbackArgs);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
LOG(("Could not run callback app, last error: %d", GetLastError()));
|
||||
if (environmentBlock) {
|
||||
DestroyEnvironmentBlock(environmentBlock);
|
||||
}
|
||||
if (callbackArgs) {
|
||||
free(callbackArgs);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Maintenance service file system monitoring.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Brian R. Bondy <netzen@gmail.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#define STOP_CMD L"stop"
|
||||
|
||||
BOOL StartDirectoryChangeMonitor();
|
||||
BOOL GetUpdateDirectoryPath(LPWSTR);
|
|
@ -21,6 +21,7 @@
|
|||
# Robert Strong <robert.bugzilla@gmail.com>
|
||||
# Ehsan Akhgari <ehsan.akhgari@gmail.com>
|
||||
# Amir Szekely <kichik@gmail.com>
|
||||
# Brian R. Bondy <netzen@gmail.com>
|
||||
#
|
||||
# Alternatively, the contents of this file may be used under the terms of
|
||||
# either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
|
@ -6680,6 +6681,40 @@
|
|||
!verbose pop
|
||||
!macroend
|
||||
|
||||
!macro IsUserAdmin
|
||||
; Copied from: http://nsis.sourceforge.net/IsUserAdmin
|
||||
Function IsUserAdmin
|
||||
Push $R0
|
||||
Push $R1
|
||||
Push $R2
|
||||
|
||||
ClearErrors
|
||||
UserInfo::GetName
|
||||
IfErrors Win9x
|
||||
Pop $R1
|
||||
UserInfo::GetAccountType
|
||||
Pop $R2
|
||||
|
||||
StrCmp $R2 "Admin" 0 Continue
|
||||
StrCpy $R0 "true"
|
||||
Goto Done
|
||||
|
||||
Continue:
|
||||
|
||||
StrCmp $R2 "" Win9x
|
||||
StrCpy $R0 "false"
|
||||
Goto Done
|
||||
|
||||
Win9x:
|
||||
StrCpy $R0 "true"
|
||||
|
||||
Done:
|
||||
Pop $R2
|
||||
Pop $R1
|
||||
Exch $R0
|
||||
FunctionEnd
|
||||
!macroend
|
||||
|
||||
/**
|
||||
* Retrieve if present or generate and store a 64 bit hash of an install path
|
||||
* using the City Hash algorithm. On return the resulting id is saved in the
|
||||
|
|
|
@ -63,6 +63,7 @@ CUSTOM_NSIS_PLUGINS = \
|
|||
InvokeShellVerb.dll \
|
||||
ShellLink.dll \
|
||||
UAC.dll \
|
||||
ServicesHelper.dll \
|
||||
$(NULL)
|
||||
|
||||
$(CONFIG_DIR)/setup.exe::
|
||||
|
@ -99,3 +100,10 @@ uninstaller::
|
|||
cd $(CONFIG_DIR) && $(MAKENSISU) uninstaller.nsi
|
||||
$(NSINSTALL) -D $(DIST)/bin/uninstall
|
||||
cp $(CONFIG_DIR)/helper.exe $(DIST)/bin/uninstall
|
||||
|
||||
ifdef MOZ_MAINTENANCE_SERVICE
|
||||
maintenanceservice_installer::
|
||||
cd $(CONFIG_DIR) && $(MAKENSISU) maintenanceservice_installer.nsi
|
||||
$(NSINSTALL) -D $(DIST)/bin/
|
||||
cp $(CONFIG_DIR)/maintenanceservice_installer.exe $(DIST)/bin
|
||||
endif
|
||||
|
|
|
@ -49,5 +49,6 @@ export NO_SHUNT = 1
|
|||
USE_STATIC_LIBS = 1
|
||||
|
||||
CPPSRCS = readstrings.cpp
|
||||
EXPORTS = readstrings.h
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
|
|
@ -52,6 +52,7 @@ ifdef MOZ_UPDATER
|
|||
DIRS = ../readstrings
|
||||
|
||||
ifneq ($(OS_TARGET),Android)
|
||||
DIRS += common
|
||||
DIRS += updater
|
||||
endif
|
||||
|
||||
|
|
|
@ -0,0 +1,72 @@
|
|||
# ***** BEGIN LICENSE BLOCK *****
|
||||
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public License Version
|
||||
# 1.1 (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
# http://www.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS" basis,
|
||||
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
# for the specific language governing rights and limitations under the
|
||||
# License.
|
||||
#
|
||||
# The Original Code is Mozilla maintenance service build.
|
||||
#
|
||||
# The Initial Developer of the Original Code is
|
||||
# Mozilla Foundation.
|
||||
# Portions created by the Initial Developer are Copyright (C) 2011
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Brian R. Bondy <netzen@gmail.com>
|
||||
#
|
||||
# Alternatively, the contents of this file may be used under the terms of
|
||||
# either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
# in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
# of those above. If you wish to allow use of your version of this file only
|
||||
# under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
# use your version of this file under the terms of the MPL, indicate your
|
||||
# decision by deleting the provisions above and replace them with the notice
|
||||
# and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
# the provisions above, a recipient may use your version of this file under
|
||||
# the terms of any one of the MPL, the GPL or the LGPL.
|
||||
#
|
||||
# ***** END LICENSE BLOCK *****
|
||||
|
||||
DEPTH = ../../../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
MODULE = libupdatecommon
|
||||
LIBRARY_NAME = updatecommon
|
||||
FORCE_STATIC_LIB =1
|
||||
LIBXUL_LIBRARY = 1
|
||||
ifeq ($(OS_ARCH),WINNT)
|
||||
USE_STATIC_LIBS = 1
|
||||
endif
|
||||
|
||||
CPPSRCS = \
|
||||
updatelogging.cpp \
|
||||
$(NULL)
|
||||
|
||||
EXPORTS = updatelogging.h \
|
||||
updatedefines.h \
|
||||
$(NULL)
|
||||
|
||||
ifeq ($(MOZ_WIDGET_TOOLKIT),windows)
|
||||
CPPSRCS += launchwinprocess.cpp \
|
||||
uachelper.cpp \
|
||||
$(NULL)
|
||||
|
||||
EXPORTS = launchwinprocess.h \
|
||||
uachelper.h \
|
||||
$(NULL)
|
||||
endif
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
|
@ -0,0 +1,259 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is common code between maintenanceservice and updater
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Brian R. Bondy <netzen@gmail.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include <windows.h>
|
||||
#include <shlwapi.h>
|
||||
|
||||
BOOL PathAppendSafe(LPWSTR base, LPCWSTR extra);
|
||||
|
||||
|
||||
/**
|
||||
* Obtains the path of a file in the same directory as the specified file.
|
||||
*
|
||||
* @param destinationBuffer A buffer of size MAX_PATH + 1 to store the result.
|
||||
* @param siblingFIlePath The path of another file in the same directory
|
||||
* @param newFileName The filename of another file in the same directory
|
||||
* @return TRUE if successful
|
||||
*/
|
||||
BOOL
|
||||
PathGetSiblingFilePath(LPWSTR destinationBuffer,
|
||||
LPCWSTR siblingFilePath,
|
||||
LPCWSTR newFileName)
|
||||
{
|
||||
if (wcslen(siblingFilePath) >= MAX_PATH) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
wcscpy(destinationBuffer, siblingFilePath);
|
||||
if (!PathRemoveFileSpecW(destinationBuffer)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (wcslen(destinationBuffer) + wcslen(newFileName) >= MAX_PATH) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return PathAppendSafe(destinationBuffer, newFileName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Launch the post update application as the specified user (helper.exe).
|
||||
* It takes in the path of the callback application to calculate the path
|
||||
* of helper.exe. For service updates this is called from both the system
|
||||
* account and the current user account.
|
||||
*
|
||||
* @param appExe The path to the callback application binary.
|
||||
* @param updateInfoDir The directory where update info is stored.
|
||||
* @param forceSync If true even if the ini file specifies async, the
|
||||
* process will wait for termination of PostUpdate.
|
||||
* @param userToken The user token to run as, if NULL the current user
|
||||
* will be used.
|
||||
*/
|
||||
BOOL
|
||||
LaunchWinPostProcess(const WCHAR *appExe,
|
||||
const WCHAR *updateInfoDir,
|
||||
bool forceSync,
|
||||
HANDLE userToken)
|
||||
{
|
||||
WCHAR workingDirectory[MAX_PATH + 1];
|
||||
wcscpy(workingDirectory, appExe);
|
||||
if (!PathRemoveFileSpecW(workingDirectory)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Launch helper.exe to perform post processing (e.g. registry and log file
|
||||
// modifications) for the update.
|
||||
WCHAR inifile[MAX_PATH + 1];
|
||||
if (!PathGetSiblingFilePath(inifile, appExe, L"updater.ini")) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
WCHAR exefile[MAX_PATH + 1];
|
||||
WCHAR exearg[MAX_PATH + 1];
|
||||
WCHAR exeasync[10];
|
||||
bool async = true;
|
||||
if (!GetPrivateProfileStringW(L"PostUpdateWin", L"ExeRelPath", NULL, exefile,
|
||||
MAX_PATH + 1, inifile)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!GetPrivateProfileStringW(L"PostUpdateWin", L"ExeArg", NULL, exearg,
|
||||
MAX_PATH + 1, inifile))
|
||||
return FALSE;
|
||||
|
||||
if (!GetPrivateProfileStringW(L"PostUpdateWin", L"ExeAsync", L"TRUE",
|
||||
exeasync,
|
||||
sizeof(exeasync)/sizeof(exeasync[0]), inifile))
|
||||
return FALSE;
|
||||
|
||||
WCHAR exefullpath[MAX_PATH + 1];
|
||||
if (!PathGetSiblingFilePath(exefullpath, appExe, exefile)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
WCHAR dlogFile[MAX_PATH + 1];
|
||||
if (!PathGetSiblingFilePath(dlogFile, exefullpath, L"uninstall.update")) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
WCHAR slogFile[MAX_PATH + 1];
|
||||
wcscpy(slogFile, updateInfoDir);
|
||||
if (!PathAppendSafe(slogFile, L"update.log")) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
WCHAR dummyArg[14];
|
||||
wcscpy(dummyArg, L"argv0ignored ");
|
||||
|
||||
size_t len = wcslen(exearg) + wcslen(dummyArg);
|
||||
WCHAR *cmdline = (WCHAR *) malloc((len + 1) * sizeof(WCHAR));
|
||||
if (!cmdline) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
wcscpy(cmdline, dummyArg);
|
||||
wcscat(cmdline, exearg);
|
||||
|
||||
if (forceSync ||
|
||||
!_wcsnicmp(exeasync, L"false", 6) ||
|
||||
!_wcsnicmp(exeasync, L"0", 2)) {
|
||||
async = false;
|
||||
}
|
||||
|
||||
// We want to launch the post update helper app to update the Windows
|
||||
// registry even if there is a failure with removing the uninstall.update
|
||||
// file or copying the update.log file.
|
||||
CopyFileW(slogFile, dlogFile, false);
|
||||
|
||||
STARTUPINFOW si = {sizeof(si), 0};
|
||||
si.lpDesktop = L"";
|
||||
PROCESS_INFORMATION pi = {0};
|
||||
|
||||
bool ok;
|
||||
if (userToken) {
|
||||
ok = CreateProcessAsUserW(userToken,
|
||||
exefullpath,
|
||||
cmdline,
|
||||
NULL, // no special security attributes
|
||||
NULL, // no special thread attributes
|
||||
false, // don't inherit filehandles
|
||||
0, // No special process creation flags
|
||||
NULL, // inherit my environment
|
||||
workingDirectory,
|
||||
&si,
|
||||
&pi);
|
||||
} else {
|
||||
ok = CreateProcessW(exefullpath,
|
||||
cmdline,
|
||||
NULL, // no special security attributes
|
||||
NULL, // no special thread attributes
|
||||
false, // don't inherit filehandles
|
||||
0, // No special process creation flags
|
||||
NULL, // inherit my environment
|
||||
workingDirectory,
|
||||
&si,
|
||||
&pi);
|
||||
}
|
||||
free(cmdline);
|
||||
if (ok) {
|
||||
if (!async)
|
||||
WaitForSingleObject(pi.hProcess, INFINITE);
|
||||
CloseHandle(pi.hProcess);
|
||||
CloseHandle(pi.hThread);
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the upgrade process for update of the service if it is
|
||||
* already installed.
|
||||
*
|
||||
* @param argc The argc value normally sent to updater.exe
|
||||
* @param argv The argv value normally sent to updater.exe
|
||||
* @return TRUE if successful
|
||||
*/
|
||||
BOOL
|
||||
StartServiceUpdate(int argc, LPWSTR *argv)
|
||||
{
|
||||
if (argc < 2) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Get a handle to the local computer SCM database
|
||||
SC_HANDLE manager = OpenSCManager(NULL, NULL,
|
||||
SC_MANAGER_ALL_ACCESS);
|
||||
if (!manager) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Open the service
|
||||
SC_HANDLE svc = OpenServiceW(manager, L"MozillaMaintenance",
|
||||
SERVICE_ALL_ACCESS);
|
||||
if (!svc) {
|
||||
CloseServiceHandle(manager);
|
||||
return FALSE;
|
||||
}
|
||||
CloseServiceHandle(svc);
|
||||
CloseServiceHandle(manager);
|
||||
|
||||
// If we reach here, then the service is installed, so
|
||||
// proceed with upgrading it.
|
||||
|
||||
STARTUPINFOW si = {0};
|
||||
si.cb = sizeof(STARTUPINFOW);
|
||||
// No particular desktop because no UI
|
||||
si.lpDesktop = L"";
|
||||
PROCESS_INFORMATION pi = {0};
|
||||
|
||||
WCHAR maintserviceInstallerPath[MAX_PATH + 1];
|
||||
wcscpy(maintserviceInstallerPath, argv[2]);
|
||||
PathAppendSafe(maintserviceInstallerPath,
|
||||
L"maintenanceservice_installer.exe");
|
||||
WCHAR cmdLine[64];
|
||||
wcscpy(cmdLine, L"dummyparam.exe /Upgrade");
|
||||
BOOL svcUpdateProcessStarted = CreateProcessW(maintserviceInstallerPath,
|
||||
cmdLine,
|
||||
NULL, NULL, FALSE,
|
||||
CREATE_DEFAULT_ERROR_MODE |
|
||||
CREATE_UNICODE_ENVIRONMENT,
|
||||
NULL, argv[2], &si, &pi);
|
||||
if (svcUpdateProcessStarted) {
|
||||
CloseHandle(pi.hProcess);
|
||||
CloseHandle(pi.hThread);
|
||||
}
|
||||
return svcUpdateProcessStarted;
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is common code between maintenanceservice and updater
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Brian R. Bondy <netzen@gmail.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
BOOL LaunchWinPostProcess(const WCHAR *appExe,
|
||||
const WCHAR *updateInfoDir,
|
||||
bool forceSync,
|
||||
HANDLE userToken);
|
||||
BOOL StartServiceUpdate(int argc, LPWSTR *argv);
|
|
@ -0,0 +1,101 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Maintenance service UAC helper functions.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Brian R. Bondy <netzen@gmail.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include <windows.h>
|
||||
#include "uachelper.h"
|
||||
|
||||
typedef BOOL (WINAPI *LPWTSQueryUserToken)(ULONG, PHANDLE);
|
||||
|
||||
/**
|
||||
* Determines if the OS is vista or later
|
||||
*
|
||||
* @return TRUE if the OS is vista or later.
|
||||
*/
|
||||
BOOL
|
||||
UACHelper::IsVistaOrLater()
|
||||
{
|
||||
// Check if we are running Vista or later.
|
||||
OSVERSIONINFO osInfo;
|
||||
osInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
|
||||
return GetVersionEx(&osInfo) && osInfo.dwMajorVersion >= 6;
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a user token for the given session ID
|
||||
*
|
||||
* @param sessionID The session ID for the token to obtain
|
||||
* @return A handle to the token to obtain which will be primary if enough
|
||||
* permissions exist. Caller should close the handle.
|
||||
*/
|
||||
HANDLE
|
||||
UACHelper::OpenUserToken(DWORD sessionID)
|
||||
{
|
||||
HMODULE module = LoadLibraryW(L"wtsapi32.dll");
|
||||
HANDLE token = NULL;
|
||||
LPWTSQueryUserToken wtsQueryUserToken =
|
||||
(LPWTSQueryUserToken)GetProcAddress(module, "WTSQueryUserToken");
|
||||
if (wtsQueryUserToken) {
|
||||
wtsQueryUserToken(sessionID, &token);
|
||||
}
|
||||
FreeLibrary(module);
|
||||
return token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a linked token for the specified token.
|
||||
*
|
||||
* @param token The token to get the linked token from
|
||||
* @return A linked token or NULL if one does not exist.
|
||||
* Caller should close the handle.
|
||||
*/
|
||||
HANDLE
|
||||
UACHelper::OpenLinkedToken(HANDLE token)
|
||||
{
|
||||
// Magic below...
|
||||
// UAC creates 2 tokens. One is the restricted token which we have.
|
||||
// the other is the UAC elevated one. Since we are running as a service
|
||||
// as the system account we have access to both.
|
||||
TOKEN_LINKED_TOKEN tlt;
|
||||
HANDLE hNewLinkedToken = NULL;
|
||||
DWORD len;
|
||||
if (GetTokenInformation(token, (TOKEN_INFORMATION_CLASS)TokenLinkedToken,
|
||||
&tlt, sizeof(TOKEN_LINKED_TOKEN), &len)) {
|
||||
token = tlt.LinkedToken;
|
||||
hNewLinkedToken = token;
|
||||
}
|
||||
return hNewLinkedToken;
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Maintenance service UAC helper functions.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Brian R. Bondy <netzen@gmail.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _UACHELPER_H_
|
||||
#define _UACHELPER_H_
|
||||
|
||||
class UACHelper
|
||||
{
|
||||
public:
|
||||
static BOOL IsVistaOrLater();
|
||||
static HANDLE OpenUserToken(DWORD sessionID);
|
||||
static HANDLE OpenLinkedToken(HANDLE token);
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,143 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is common code between maintenanceservice and updater
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Brian R. Bondy <netzen@gmail.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef UPDATEDEFINES_H
|
||||
#define UPDATEDEFINES_H
|
||||
|
||||
#include "prtypes.h"
|
||||
#include "readstrings.h"
|
||||
|
||||
#ifndef MAXPATHLEN
|
||||
# ifdef PATH_MAX
|
||||
# define MAXPATHLEN PATH_MAX
|
||||
# elif defined(MAX_PATH)
|
||||
# define MAXPATHLEN MAX_PATH
|
||||
# elif defined(_MAX_PATH)
|
||||
# define MAXPATHLEN _MAX_PATH
|
||||
# elif defined(CCHMAXPATH)
|
||||
# define MAXPATHLEN CCHMAXPATH
|
||||
# else
|
||||
# define MAXPATHLEN 1024
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(XP_WIN)
|
||||
# include <windows.h>
|
||||
# include <direct.h>
|
||||
# include <io.h>
|
||||
|
||||
# define F_OK 00
|
||||
# define W_OK 02
|
||||
# define R_OK 04
|
||||
# define S_ISDIR(s) (((s) & _S_IFMT) == _S_IFDIR)
|
||||
# define S_ISREG(s) (((s) & _S_IFMT) == _S_IFREG)
|
||||
|
||||
# define access _access
|
||||
|
||||
# define putenv _putenv
|
||||
# define stat _stat
|
||||
# define DELETE_DIR L"tobedeleted"
|
||||
# define CALLBACK_BACKUP_EXT L".moz-callback"
|
||||
|
||||
# define LOG_S "%S"
|
||||
# define NS_T(str) L ## str
|
||||
// On Windows, _snprintf and _snwprintf don't guarantee null termination. These
|
||||
// macros always leave room in the buffer for null termination and set the end
|
||||
// of the buffer to null in case the string is larger than the buffer. Having
|
||||
// multiple nulls in a string is fine and this approach is simpler (possibly
|
||||
// faster) than calculating the string length to place the null terminator and
|
||||
// truncates the string as _snprintf and _snwprintf do on other platforms.
|
||||
# define snprintf(dest, count, fmt, ...) \
|
||||
PR_BEGIN_MACRO \
|
||||
int _count = count - 1; \
|
||||
_snprintf(dest, _count, fmt, ##__VA_ARGS__); \
|
||||
dest[_count] = '\0'; \
|
||||
PR_END_MACRO
|
||||
#define NS_tsnprintf(dest, count, fmt, ...) \
|
||||
PR_BEGIN_MACRO \
|
||||
int _count = count - 1; \
|
||||
_snwprintf(dest, _count, fmt, ##__VA_ARGS__); \
|
||||
dest[_count] = L'\0'; \
|
||||
PR_END_MACRO
|
||||
# define NS_taccess _waccess
|
||||
# define NS_tchdir _wchdir
|
||||
# define NS_tchmod _wchmod
|
||||
# define NS_tfopen _wfopen
|
||||
# define NS_tmkdir(path, perms) _wmkdir(path)
|
||||
# define NS_tremove _wremove
|
||||
// _wrename is used to avoid the link tracking service.
|
||||
# define NS_trename _wrename
|
||||
# define NS_trmdir _wrmdir
|
||||
# define NS_tstat _wstat
|
||||
# define NS_tstrcat wcscat
|
||||
# define NS_tstrcmp wcscmp
|
||||
# define NS_tstrcpy wcscpy
|
||||
# define NS_tstrlen wcslen
|
||||
# define NS_tstrrchr wcsrchr
|
||||
# define NS_tstrstr wcsstr
|
||||
#else
|
||||
# include <sys/wait.h>
|
||||
# include <unistd.h>
|
||||
# include <fts.h>
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
# include <sys/time.h>
|
||||
#endif
|
||||
|
||||
# define LOG_S "%s"
|
||||
# define NS_T(str) str
|
||||
# define NS_tsnprintf snprintf
|
||||
# define NS_taccess access
|
||||
# define NS_tchdir chdir
|
||||
# define NS_tchmod chmod
|
||||
# define NS_tfopen fopen
|
||||
# define NS_tmkdir mkdir
|
||||
# define NS_tremove remove
|
||||
# define NS_trename rename
|
||||
# define NS_trmdir rmdir
|
||||
# define NS_tstat stat
|
||||
# define NS_tstrcat strcat
|
||||
# define NS_tstrcmp strcmp
|
||||
# define NS_tstrcpy strcpy
|
||||
# define NS_tstrlen strlen
|
||||
# define NS_tstrrchr strrchr
|
||||
# define NS_tstrstr strstr
|
||||
#endif
|
||||
|
||||
#define BACKUP_EXT NS_T(".moz-backup")
|
||||
|
||||
#endif
|
|
@ -0,0 +1,87 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is common code between maintenanceservice and updater
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Brian R. Bondy <netzen@gmail.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#if defined(XP_WIN)
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "updatelogging.h"
|
||||
|
||||
UpdateLog* UpdateLog::primaryLog = NULL;
|
||||
|
||||
UpdateLog::UpdateLog() : logFP(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
void UpdateLog::Init(NS_tchar* sourcePath, NS_tchar* fileName)
|
||||
{
|
||||
if (logFP)
|
||||
return;
|
||||
|
||||
this->sourcePath = sourcePath;
|
||||
NS_tchar logFile[MAXPATHLEN];
|
||||
NS_tsnprintf(logFile, sizeof(logFile)/sizeof(logFile[0]),
|
||||
NS_T("%s/%s"), sourcePath, fileName);
|
||||
|
||||
logFP = NS_tfopen(logFile, NS_T("w"));
|
||||
}
|
||||
|
||||
void UpdateLog::Finish()
|
||||
{
|
||||
if (!logFP)
|
||||
return;
|
||||
|
||||
fclose(logFP);
|
||||
logFP = NULL;
|
||||
}
|
||||
|
||||
void UpdateLog::Printf(const char *fmt, ... )
|
||||
{
|
||||
if (!logFP)
|
||||
return;
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
vfprintf(logFP, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is common code between maintenanceservice and updater
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Brian R. Bondy <netzen@gmail.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef UPDATELOGGING_H
|
||||
#define UPDATELOGGING_H
|
||||
|
||||
#include "updatedefines.h"
|
||||
#include <stdio.h>
|
||||
|
||||
class UpdateLog
|
||||
{
|
||||
public:
|
||||
static UpdateLog & GetPrimaryLog()
|
||||
{
|
||||
if (!primaryLog) {
|
||||
primaryLog = new UpdateLog();
|
||||
}
|
||||
return *primaryLog;
|
||||
}
|
||||
|
||||
void Init(NS_tchar* sourcePath, NS_tchar* fileName);
|
||||
void Finish();
|
||||
void Printf(const char *fmt, ... );
|
||||
|
||||
~UpdateLog()
|
||||
{
|
||||
delete primaryLog;
|
||||
}
|
||||
|
||||
protected:
|
||||
UpdateLog();
|
||||
FILE *logFP;
|
||||
NS_tchar* sourcePath;
|
||||
|
||||
static UpdateLog* primaryLog;
|
||||
};
|
||||
|
||||
#define LOG(args) UpdateLog::GetPrimaryLog().Printf args
|
||||
#define LogInit(PATHNAME_, FILENAME_) \
|
||||
UpdateLog::GetPrimaryLog().Init(PATHNAME_, FILENAME_)
|
||||
#define LogFinish() UpdateLog::GetPrimaryLog().Finish()
|
||||
|
||||
#endif
|
|
@ -68,6 +68,7 @@ const URI_UPDATES_PROPERTIES = "chrome://mozapps/locale/update/updates.properti
|
|||
|
||||
const STATE_DOWNLOADING = "downloading";
|
||||
const STATE_PENDING = "pending";
|
||||
const STATE_PENDING_SVC = "pending-service";
|
||||
const STATE_APPLYING = "applying";
|
||||
const STATE_SUCCEEDED = "succeeded";
|
||||
const STATE_DOWNLOAD_FAILED = "download-failed";
|
||||
|
@ -443,6 +444,7 @@ var gUpdates = {
|
|||
// the Update.
|
||||
switch (state) {
|
||||
case STATE_PENDING:
|
||||
case STATE_PENDING_SVC:
|
||||
this.sourceEvent = SRCEVT_BACKGROUND;
|
||||
aCallback("finishedBackground");
|
||||
return;
|
||||
|
@ -1680,6 +1682,7 @@ var gErrorPatchingPage = {
|
|||
onWizardNext: function() {
|
||||
switch (gUpdates.update.selectedPatch.state) {
|
||||
case STATE_PENDING:
|
||||
case STATE_PENDING_SVC:
|
||||
gUpdates.wiz.goTo("finished");
|
||||
break;
|
||||
case STATE_DOWNLOADING:
|
||||
|
|
|
@ -245,12 +245,13 @@ interface nsIUpdate : nsISupports
|
|||
|
||||
/**
|
||||
* The state of the selected patch:
|
||||
* "downloading" The update is being downloaded.
|
||||
* "pending" The update is ready to be applied.
|
||||
* "applying" The update is being applied.
|
||||
* "succeeded" The update was successfully applied.
|
||||
* "download-failed" The update failed to be downloaded.
|
||||
* "failed" The update failed to be applied.
|
||||
* "downloading" The update is being downloaded.
|
||||
* "pending" The update is ready to be applied.
|
||||
* "pending-service" The update is ready to be applied with the service.
|
||||
* "applying" The update is being applied.
|
||||
* "succeeded" The update was successfully applied.
|
||||
* "download-failed" The update failed to be downloaded.
|
||||
* "failed" The update failed to be applied.
|
||||
*/
|
||||
attribute AString state;
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
# Alexander J. Vincent <ajvincent@gmail.com>
|
||||
# Dão Gottwald <dao@mozilla.com>
|
||||
# Robert Strong <robert.bugzilla@gmail.com>
|
||||
# Brian R. Bondy <netzen@gmail.com>
|
||||
#
|
||||
# Alternatively, the contents of this file may be used under the terms of
|
||||
# either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
|
@ -81,6 +82,9 @@ const PREF_APP_UPDATE_SILENT = "app.update.silent";
|
|||
const PREF_APP_UPDATE_URL = "app.update.url";
|
||||
const PREF_APP_UPDATE_URL_DETAILS = "app.update.url.details";
|
||||
const PREF_APP_UPDATE_URL_OVERRIDE = "app.update.url.override";
|
||||
const PREF_APP_UPDATE_SERVICE_ENABLED = "app.update.service.enabled";
|
||||
const PREF_APP_UPDATE_SERVICE_ERRORS = "app.update.service.errors";
|
||||
const PREF_APP_UPDATE_SERVICE_MAX_ERRORS = "app.update.service.maxErrors";
|
||||
|
||||
const PREF_PARTNER_BRANCH = "app.partner.";
|
||||
const PREF_APP_DISTRIBUTION = "distribution.id";
|
||||
|
@ -129,6 +133,7 @@ const FILE_UPDATE_LOCALE = "update.locale";
|
|||
const STATE_NONE = "null";
|
||||
const STATE_DOWNLOADING = "downloading";
|
||||
const STATE_PENDING = "pending";
|
||||
const STATE_PENDING_SVC = "pending-service";
|
||||
const STATE_APPLYING = "applying";
|
||||
const STATE_SUCCEEDED = "succeeded";
|
||||
const STATE_DOWNLOAD_FAILED = "download-failed";
|
||||
|
@ -138,6 +143,10 @@ const STATE_FAILED = "failed";
|
|||
const WRITE_ERROR = 7;
|
||||
const UNEXPECTED_ERROR = 8;
|
||||
const ELEVATION_CANCELED = 9;
|
||||
const SERVICE_UPDATER_COULD_NOT_BE_STARTED = 16000;
|
||||
const SERVICE_NOT_ENOUGH_COMMAND_LINE_ARGS = 16001;
|
||||
const SERVICE_UPDATER_SIGN_ERROR = 16002;
|
||||
const SERVICE_CALLBACK_SIGN_ERROR = 16003;
|
||||
|
||||
const CERT_ATTR_CHECK_FAILED_NO_UPDATE = 100;
|
||||
const CERT_ATTR_CHECK_FAILED_HAS_UPDATE = 101;
|
||||
|
@ -149,6 +158,10 @@ const DOWNLOAD_FOREGROUND_INTERVAL = 0;
|
|||
|
||||
const UPDATE_WINDOW_NAME = "Update:Wizard";
|
||||
|
||||
// The number of consecutive failures when updating using the service before
|
||||
// setting the app.update.service.enabled preference to false.
|
||||
const DEFAULT_SERVICE_MAX_ERRORS = 10;
|
||||
|
||||
var gLocale = null;
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "gLogEnabled", function aus_gLogEnabled() {
|
||||
|
@ -461,7 +474,7 @@ function LOG(string) {
|
|||
# @param defaultValue
|
||||
# The default value to return in the event the preference has
|
||||
# no setting
|
||||
# @returns The value of the preference, or undefined if there was no
|
||||
# @return The value of the preference, or undefined if there was no
|
||||
# user or default value.
|
||||
*/
|
||||
function getPref(func, preference, defaultValue) {
|
||||
|
@ -530,7 +543,7 @@ function getUpdateFile(pathArray) {
|
|||
* @param defaultCode
|
||||
* The default code to look up should human readable status text
|
||||
* not exist for |code|
|
||||
* @returns A human readable status text string
|
||||
* @return A human readable status text string
|
||||
*/
|
||||
function getStatusTextFromCode(code, defaultCode) {
|
||||
var reason;
|
||||
|
@ -550,7 +563,7 @@ function getStatusTextFromCode(code, defaultCode) {
|
|||
|
||||
/**
|
||||
* Get the Active Updates directory
|
||||
* @returns The active updates directory, as a nsIFile object
|
||||
* @return The active updates directory, as a nsIFile object
|
||||
*/
|
||||
function getUpdatesDir() {
|
||||
// Right now, we only support downloading one patch at a time, so we always
|
||||
|
@ -563,7 +576,7 @@ function getUpdatesDir() {
|
|||
* directory.
|
||||
* @param dir
|
||||
* The dir to look for an update.status file in
|
||||
* @returns The status value of the update.
|
||||
* @return The status value of the update.
|
||||
*/
|
||||
function readStatusFile(dir) {
|
||||
var statusFile = dir.clone();
|
||||
|
@ -589,6 +602,22 @@ function writeStatusFile(dir, state) {
|
|||
writeStringToFile(statusFile, state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the service should be used to attempt an update
|
||||
* or not. For now this is only when PREF_APP_UPDATE_SERVICE_ENABLED
|
||||
* is true and we have Firefox.
|
||||
*
|
||||
* @return true if the service should be used for updates.
|
||||
*/
|
||||
function shouldUseService() {
|
||||
#ifdef MOZ_MAINTENANCE_SERVICE
|
||||
return getPref("getBoolPref",
|
||||
PREF_APP_UPDATE_SERVICE_ENABLED, false);
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
# Writes the update's application version to a file in the patch directory. If
|
||||
# the update doesn't provide application version information via the
|
||||
|
@ -1399,7 +1428,34 @@ UpdateService.prototype = {
|
|||
writeStatusFile(getUpdatesDir(), update.state = STATE_PENDING);
|
||||
return;
|
||||
}
|
||||
else if (update.errorCode == ELEVATION_CANCELED) {
|
||||
|
||||
if (update.errorCode == ELEVATION_CANCELED) {
|
||||
writeStatusFile(getUpdatesDir(), update.state = STATE_PENDING);
|
||||
return;
|
||||
}
|
||||
|
||||
if (update.errorCode == SERVICE_UPDATER_COULD_NOT_BE_STARTED ||
|
||||
update.errorCode == SERVICE_NOT_ENOUGH_COMMAND_LINE_ARGS ||
|
||||
update.errorCode == SERVICE_UPDATER_SIGN_ERROR ||
|
||||
update.errorCode == SERVICE_CALLBACK_SIGN_ERROR) {
|
||||
var failCount = getPref("getIntPref",
|
||||
PREF_APP_UPDATE_SERVICE_ERRORS, 0);
|
||||
var maxFail = getPref("getIntPref",
|
||||
PREF_APP_UPDATE_SERVICE_MAX_ERRORS,
|
||||
DEFAULT_SERVICE_MAX_ERRORS);
|
||||
|
||||
// As a safety, when the service reaches maximum failures, it will
|
||||
// disable itself and fallback to using the normal update mechanism
|
||||
// without the service.
|
||||
if (failCount >= maxFail) {
|
||||
Services.prefs.setBoolPref(PREF_APP_UPDATE_SERVICE_ENABLED, false);
|
||||
Services.prefs.clearUserPref(PREF_APP_UPDATE_SERVICE_ERRORS);
|
||||
} else {
|
||||
failCount++;
|
||||
Services.prefs.setIntPref(PREF_APP_UPDATE_SERVICE_ERRORS,
|
||||
failCount);
|
||||
}
|
||||
|
||||
writeStatusFile(getUpdatesDir(), update.state = STATE_PENDING);
|
||||
return;
|
||||
}
|
||||
|
@ -1522,7 +1578,7 @@ UpdateService.prototype = {
|
|||
* be offered.
|
||||
* @param updates
|
||||
* An array of available nsIUpdate items
|
||||
* @returns The nsIUpdate to offer.
|
||||
* @return The nsIUpdate to offer.
|
||||
*/
|
||||
selectUpdate: function AUS_selectUpdate(updates) {
|
||||
if (updates.length == 0)
|
||||
|
@ -2011,7 +2067,7 @@ UpdateManager.prototype = {
|
|||
* Loads an updates.xml formatted file into an array of nsIUpdate items.
|
||||
* @param file
|
||||
* A nsIFile for the updates.xml file
|
||||
* @returns The array of nsIUpdate items held in the file.
|
||||
* @return The array of nsIUpdate items held in the file.
|
||||
*/
|
||||
_loadXMLFileIntoArray: function UM__loadXMLFileIntoArray(file) {
|
||||
if (!file.exists()) {
|
||||
|
@ -2195,7 +2251,7 @@ UpdateManager.prototype = {
|
|||
for (let i = updates.length - 1; i >= 0; --i) {
|
||||
let state = updates[i].state;
|
||||
if (state == STATE_NONE || state == STATE_DOWNLOADING ||
|
||||
state == STATE_PENDING) {
|
||||
state == STATE_PENDING || state == STATE_PENDING_SVC) {
|
||||
updates.splice(i, 1);
|
||||
}
|
||||
}
|
||||
|
@ -2530,7 +2586,8 @@ Downloader.prototype = {
|
|||
* Whether or not a patch has been downloaded and staged for installation.
|
||||
*/
|
||||
get patchIsStaged() {
|
||||
return readStatusFile(getUpdatesDir()) == STATE_PENDING;
|
||||
var readState = readStatusFile(getUpdatesDir());
|
||||
return readState == STATE_PENDING || readState == STATE_PENDING_SVC;
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -2582,7 +2639,7 @@ Downloader.prototype = {
|
|||
* A nsIUpdate object to select a patch from
|
||||
* @param updateDir
|
||||
* A nsIFile representing the update directory
|
||||
* @returns A nsIUpdatePatch object to download
|
||||
* @return A nsIUpdatePatch object to download
|
||||
*/
|
||||
_selectPatch: function Downloader__selectPatch(update, updateDir) {
|
||||
// Given an update to download, we will always try to download the patch
|
||||
|
@ -2592,7 +2649,7 @@ Downloader.prototype = {
|
|||
* Return the first UpdatePatch with the given type.
|
||||
* @param type
|
||||
* The type of the patch ("complete" or "partial")
|
||||
* @returns A nsIUpdatePatch object matching the type specified
|
||||
* @return A nsIUpdatePatch object matching the type specified
|
||||
*/
|
||||
function getPatchOfType(type) {
|
||||
for (var i = 0; i < update.patchCount; ++i) {
|
||||
|
@ -2620,6 +2677,7 @@ Downloader.prototype = {
|
|||
case STATE_DOWNLOADING:
|
||||
LOG("Downloader:_selectPatch - resuming download");
|
||||
return selectedPatch;
|
||||
case STATE_PENDING_SVC:
|
||||
case STATE_PENDING:
|
||||
LOG("Downloader:_selectPatch - already downloaded and staged");
|
||||
return null;
|
||||
|
@ -2847,7 +2905,7 @@ Downloader.prototype = {
|
|||
var deleteActiveUpdate = false;
|
||||
if (Components.isSuccessCode(status)) {
|
||||
if (this._verifyDownload()) {
|
||||
state = STATE_PENDING;
|
||||
state = shouldUseService() ? STATE_PENDING_SVC : STATE_PENDING
|
||||
|
||||
// We only need to explicitly show the prompt if this is a background
|
||||
// download, since otherwise some kind of UI is already visible and
|
||||
|
|
|
@ -78,6 +78,7 @@ INI_TEST_FILES = \
|
|||
LOCAL_INCLUDES += \
|
||||
-I$(srcdir) \
|
||||
-I$(topsrcdir)/toolkit/mozapps/update \
|
||||
-I$(topsrcdir)/toolkit/mozapps/update/common \
|
||||
$(NULL)
|
||||
|
||||
MOZ_WINCONSOLE = 1
|
||||
|
|
|
@ -29,6 +29,7 @@ const SHA512_HASH_SIMPLE_MAR = "55d3e2a86acaeb0abb7a444c13bba748846fcbac7ff05" +
|
|||
const STATE_NONE = "null";
|
||||
const STATE_DOWNLOADING = "downloading";
|
||||
const STATE_PENDING = "pending";
|
||||
const STATE_PENDING_SVC = "pending-service";
|
||||
const STATE_APPLYING = "applying";
|
||||
const STATE_SUCCEEDED = "succeeded";
|
||||
const STATE_DOWNLOAD_FAILED = "download-failed";
|
||||
|
|
|
@ -55,9 +55,11 @@ PROGRAM = updater$(BIN_SUFFIX)
|
|||
MOZ_UTILS_LDFLAGS =
|
||||
MOZ_UTILS_PROGRAM_LDFLAGS =
|
||||
|
||||
LOCAL_INCLUDES += -I$(srcdir)/../../readstrings
|
||||
LOCAL_INCLUDES += -I$(srcdir)/../../readstrings \
|
||||
-I$(srcdir)/../common
|
||||
|
||||
LIBS += \
|
||||
../common/$(LIB_PREFIX)updatecommon.$(LIB_SUFFIX) \
|
||||
$(DEPTH)/modules/libmar/src/$(LIB_PREFIX)mar.$(LIB_SUFFIX) \
|
||||
../../readstrings/$(LIB_PREFIX)readstrings.$(LIB_SUFFIX) \
|
||||
$(BZ2_LIBS) \
|
||||
|
|
|
@ -39,6 +39,8 @@
|
|||
#ifndef PROGRESSUI_H__
|
||||
#define PROGRESSUI_H__
|
||||
|
||||
#include "updatedefines.h"
|
||||
|
||||
#if defined(XP_WIN)
|
||||
typedef WCHAR NS_tchar;
|
||||
#define NS_main wmain
|
||||
|
|
|
@ -69,92 +69,6 @@
|
|||
*
|
||||
* 'remove-cc' is a remove action to perform on channel change.
|
||||
*/
|
||||
|
||||
#if defined(XP_WIN)
|
||||
# include <windows.h>
|
||||
# include <direct.h>
|
||||
# include <io.h>
|
||||
|
||||
# define F_OK 00
|
||||
# define W_OK 02
|
||||
# define R_OK 04
|
||||
# define S_ISDIR(s) (((s) & _S_IFMT) == _S_IFDIR)
|
||||
# define S_ISREG(s) (((s) & _S_IFMT) == _S_IFREG)
|
||||
|
||||
# define access _access
|
||||
|
||||
# define putenv _putenv
|
||||
# define stat _stat
|
||||
# define DELETE_DIR L"tobedeleted"
|
||||
# define CALLBACK_BACKUP_EXT L".moz-callback"
|
||||
|
||||
# define LOG_S "%S"
|
||||
# define NS_T(str) L ## str
|
||||
// On Windows, _snprintf and _snwprintf don't guarantee null termination. These
|
||||
// macros always leave room in the buffer for null termination and set the end
|
||||
// of the buffer to null in case the string is larger than the buffer. Having
|
||||
// multiple nulls in a string is fine and this approach is simpler (possibly
|
||||
// faster) than calculating the string length to place the null terminator and
|
||||
// truncates the string as _snprintf and _snwprintf do on other platforms.
|
||||
# define snprintf(dest, count, fmt, ...) \
|
||||
PR_BEGIN_MACRO \
|
||||
int _count = count - 1; \
|
||||
_snprintf(dest, _count, fmt, ##__VA_ARGS__); \
|
||||
dest[_count] = '\0'; \
|
||||
PR_END_MACRO
|
||||
# define NS_tsnprintf(dest, count, fmt, ...) \
|
||||
PR_BEGIN_MACRO \
|
||||
int _count = count - 1; \
|
||||
_snwprintf(dest, _count, fmt, ##__VA_ARGS__); \
|
||||
dest[_count] = L'\0'; \
|
||||
PR_END_MACRO
|
||||
# define NS_taccess _waccess
|
||||
# define NS_tchdir _wchdir
|
||||
# define NS_tchmod _wchmod
|
||||
# define NS_tfopen _wfopen
|
||||
# define NS_tmkdir(path, perms) _wmkdir(path)
|
||||
# define NS_tremove _wremove
|
||||
// _wrename is used to avoid the link tracking service.
|
||||
# define NS_trename _wrename
|
||||
# define NS_trmdir _wrmdir
|
||||
# define NS_tstat _wstat
|
||||
# define NS_tstrcat wcscat
|
||||
# define NS_tstrcmp wcscmp
|
||||
# define NS_tstrcpy wcscpy
|
||||
# define NS_tstrlen wcslen
|
||||
# define NS_tstrrchr wcsrchr
|
||||
# define NS_tstrstr wcsstr
|
||||
#else
|
||||
# include <sys/wait.h>
|
||||
# include <unistd.h>
|
||||
# include <fts.h>
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
# include <sys/time.h>
|
||||
#endif
|
||||
|
||||
# define LOG_S "%s"
|
||||
# define NS_T(str) str
|
||||
# define NS_tsnprintf snprintf
|
||||
# define NS_taccess access
|
||||
# define NS_tchdir chdir
|
||||
# define NS_tchmod chmod
|
||||
# define NS_tfopen fopen
|
||||
# define NS_tmkdir mkdir
|
||||
# define NS_tremove remove
|
||||
# define NS_trename rename
|
||||
# define NS_trmdir rmdir
|
||||
# define NS_tstat stat
|
||||
# define NS_tstrcat strcat
|
||||
# define NS_tstrcmp strcmp
|
||||
# define NS_tstrcpy strcpy
|
||||
# define NS_tstrlen strlen
|
||||
# define NS_tstrrchr strrchr
|
||||
# define NS_tstrstr strstr
|
||||
#endif
|
||||
|
||||
#define BACKUP_EXT NS_T(".moz-backup")
|
||||
|
||||
#include "bspatch.h"
|
||||
#include "progressui.h"
|
||||
#include "archivereader.h"
|
||||
|
@ -172,6 +86,8 @@
|
|||
#include <limits.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "updatelogging.h"
|
||||
|
||||
// Amount of the progress bar to use in each of the 3 update stages,
|
||||
// should total 100.0.
|
||||
#define PROGRESS_PREPARE_SIZE 20.0f
|
||||
|
@ -196,20 +112,6 @@ void LaunchMacPostProcess(const char* aAppExe);
|
|||
# define SSIZE_MAX LONG_MAX
|
||||
#endif
|
||||
|
||||
#ifndef MAXPATHLEN
|
||||
# ifdef PATH_MAX
|
||||
# define MAXPATHLEN PATH_MAX
|
||||
# elif defined(MAX_PATH)
|
||||
# define MAXPATHLEN MAX_PATH
|
||||
# elif defined(_MAX_PATH)
|
||||
# define MAXPATHLEN _MAX_PATH
|
||||
# elif defined(CCHMAXPATH)
|
||||
# define MAXPATHLEN CCHMAXPATH
|
||||
# else
|
||||
# define MAXPATHLEN 1024
|
||||
# endif
|
||||
#endif
|
||||
|
||||
// We want to use execv to invoke the callback executable on platforms where
|
||||
// we were launched using execv. See nsUpdateDriver.cpp.
|
||||
#if defined(XP_UNIX) && !defined(XP_MACOSX)
|
||||
|
@ -217,6 +119,8 @@ void LaunchMacPostProcess(const char* aAppExe);
|
|||
#endif
|
||||
|
||||
#ifdef XP_WIN
|
||||
#include "launchwinprocess.h"
|
||||
|
||||
// Closes the handle if valid and if the updater is elevated returns with the
|
||||
// return code specified. This prevents multiple launches of the callback
|
||||
// application by preventing the elevated process from launching the callback.
|
||||
|
@ -401,47 +305,6 @@ static const NS_tchar kWhitespace[] = NS_T(" \t");
|
|||
static const NS_tchar kNL[] = NS_T("\r\n");
|
||||
static const NS_tchar kQuote[] = NS_T("\"");
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// LOGGING
|
||||
|
||||
static FILE *gLogFP = NULL;
|
||||
|
||||
static void LogInit()
|
||||
{
|
||||
if (gLogFP)
|
||||
return;
|
||||
|
||||
NS_tchar logFile[MAXPATHLEN];
|
||||
NS_tsnprintf(logFile, sizeof(logFile)/sizeof(logFile[0]),
|
||||
NS_T("%s/update.log"), gSourcePath);
|
||||
|
||||
gLogFP = NS_tfopen(logFile, NS_T("w"));
|
||||
}
|
||||
|
||||
static void LogFinish()
|
||||
{
|
||||
if (!gLogFP)
|
||||
return;
|
||||
|
||||
fclose(gLogFP);
|
||||
gLogFP = NULL;
|
||||
}
|
||||
|
||||
static void LogPrintf(const char *fmt, ... )
|
||||
{
|
||||
if (!gLogFP)
|
||||
return;
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
vfprintf(gLogFP, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
#define LOG(args) LogPrintf args
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
static inline size_t
|
||||
mmin(size_t a, size_t b)
|
||||
{
|
||||
|
@ -1519,96 +1382,7 @@ PatchIfFile::Finish(int status)
|
|||
|
||||
#ifdef XP_WIN
|
||||
#include "nsWindowsRestart.cpp"
|
||||
|
||||
static void
|
||||
LaunchWinPostProcess(const WCHAR *appExe)
|
||||
{
|
||||
// Launch helper.exe to perform post processing (e.g. registry and log file
|
||||
// modifications) for the update.
|
||||
WCHAR inifile[MAXPATHLEN];
|
||||
wcscpy(inifile, appExe);
|
||||
|
||||
WCHAR *slash = wcsrchr(inifile, '\\');
|
||||
if (!slash)
|
||||
return;
|
||||
|
||||
wcscpy(slash + 1, L"updater.ini");
|
||||
|
||||
WCHAR exefile[MAXPATHLEN];
|
||||
WCHAR exearg[MAXPATHLEN];
|
||||
WCHAR exeasync[10];
|
||||
bool async = true;
|
||||
if (!GetPrivateProfileStringW(L"PostUpdateWin", L"ExeRelPath", NULL, exefile,
|
||||
MAXPATHLEN, inifile))
|
||||
return;
|
||||
|
||||
if (!GetPrivateProfileStringW(L"PostUpdateWin", L"ExeArg", NULL, exearg,
|
||||
MAXPATHLEN, inifile))
|
||||
return;
|
||||
|
||||
if (!GetPrivateProfileStringW(L"PostUpdateWin", L"ExeAsync", L"TRUE", exeasync,
|
||||
sizeof(exeasync)/sizeof(exeasync[0]), inifile))
|
||||
return;
|
||||
|
||||
WCHAR exefullpath[MAXPATHLEN];
|
||||
wcscpy(exefullpath, appExe);
|
||||
|
||||
slash = wcsrchr(exefullpath, '\\');
|
||||
wcscpy(slash + 1, exefile);
|
||||
|
||||
WCHAR dlogFile[MAXPATHLEN];
|
||||
wcscpy(dlogFile, exefullpath);
|
||||
|
||||
slash = wcsrchr(dlogFile, '\\');
|
||||
wcscpy(slash + 1, L"uninstall.update");
|
||||
|
||||
WCHAR slogFile[MAXPATHLEN];
|
||||
NS_tsnprintf(slogFile, sizeof(slogFile)/sizeof(slogFile[0]),
|
||||
NS_T("%s/update.log"), gSourcePath);
|
||||
|
||||
WCHAR dummyArg[13];
|
||||
wcscpy(dummyArg, L"argv0ignored ");
|
||||
|
||||
size_t len = wcslen(exearg) + wcslen(dummyArg);
|
||||
WCHAR *cmdline = (WCHAR *) malloc((len + 1) * sizeof(WCHAR));
|
||||
if (!cmdline)
|
||||
return;
|
||||
|
||||
wcscpy(cmdline, dummyArg);
|
||||
wcscat(cmdline, exearg);
|
||||
|
||||
if (!_wcsnicmp(exeasync, L"false", 6) || !_wcsnicmp(exeasync, L"0", 2))
|
||||
async = false;
|
||||
|
||||
// We want to launch the post update helper app to update the Windows
|
||||
// registry even if there is a failure with removing the uninstall.update
|
||||
// file or copying the update.log file.
|
||||
NS_tremove(dlogFile);
|
||||
CopyFile(slogFile, dlogFile, false);
|
||||
|
||||
STARTUPINFOW si = {sizeof(si), 0};
|
||||
PROCESS_INFORMATION pi = {0};
|
||||
|
||||
bool ok = CreateProcessW(exefullpath,
|
||||
cmdline,
|
||||
NULL, // no special security attributes
|
||||
NULL, // no special thread attributes
|
||||
false, // don't inherit filehandles
|
||||
0, // No special process creation flags
|
||||
NULL, // inherit my environment
|
||||
NULL, // use my current directory
|
||||
&si,
|
||||
&pi);
|
||||
free(cmdline);
|
||||
|
||||
if (ok) {
|
||||
if (!async)
|
||||
WaitForSingleObject(pi.hProcess, INFINITE);
|
||||
|
||||
CloseHandle(pi.hProcess);
|
||||
CloseHandle(pi.hThread);
|
||||
}
|
||||
}
|
||||
#include "uachelper.h"
|
||||
#endif
|
||||
|
||||
static void
|
||||
|
@ -1620,15 +1394,35 @@ LaunchCallbackApp(const NS_tchar *workingDir, int argc, NS_tchar **argv)
|
|||
// Run from the specified working directory (see bug 312360). This is not
|
||||
// necessary on Windows CE since the application that launches the updater
|
||||
// passes the working directory as an --environ: command line argument.
|
||||
if(NS_tchdir(workingDir) != 0)
|
||||
if (NS_tchdir(workingDir) != 0) {
|
||||
LOG(("Warning: chdir failed\n"));
|
||||
}
|
||||
|
||||
#if defined(USE_EXECV)
|
||||
execv(argv[0], argv);
|
||||
#elif defined(XP_MACOSX)
|
||||
LaunchChild(argc, argv);
|
||||
#elif defined(MOZ_MAINTENANCE_SERVICE)
|
||||
// If updater.exe is run as session ID 0 and we have a MOZ_SESSION_ID
|
||||
// set, then get the unelevated token and use that to start the callback
|
||||
// application. Getting tokens will only work if the process is running
|
||||
// as the system account.
|
||||
DWORD myProcessID = GetCurrentProcessId();
|
||||
DWORD mySessionID = 0;
|
||||
ProcessIdToSessionId(myProcessID, &mySessionID);
|
||||
nsAutoHandle unelevatedToken(NULL);
|
||||
if (mySessionID == 0) {
|
||||
WCHAR *sessionIDStr = _wgetenv(L"MOZ_SESSION_ID");
|
||||
if (sessionIDStr) {
|
||||
// Remove the env var now that we have its value.
|
||||
int callbackSessionID = _wtoi(sessionIDStr);
|
||||
_wputenv(L"MOZ_SESSION_ID=");
|
||||
unelevatedToken.own(UACHelper::OpenUserToken(callbackSessionID));
|
||||
}
|
||||
}
|
||||
WinLaunchChild(argv[0], argc, argv, unelevatedToken);
|
||||
#elif defined(XP_WIN)
|
||||
WinLaunchChild(argv[0], argc, argv);
|
||||
WinLaunchChild(argv[0], argc, argv, NULL);
|
||||
#else
|
||||
# warning "Need implementaton of LaunchCallbackApp"
|
||||
#endif
|
||||
|
@ -1872,7 +1666,7 @@ int NS_main(int argc, NS_tchar **argv)
|
|||
}
|
||||
#endif
|
||||
|
||||
LogInit();
|
||||
LogInit(gSourcePath, NS_T("update.log"));
|
||||
LOG(("SOURCE DIRECTORY " LOG_S "\n", argv[1]));
|
||||
LOG(("DESTINATION DIRECTORY " LOG_S "\n", argv[2]));
|
||||
|
||||
|
@ -2035,7 +1829,20 @@ int NS_main(int argc, NS_tchar **argv)
|
|||
if (argc > callbackIndex) {
|
||||
#if defined(XP_WIN)
|
||||
if (gSucceeded) {
|
||||
LaunchWinPostProcess(argv[callbackIndex]);
|
||||
// The service update will only be executed if it is already installed.
|
||||
// For first time installs of the service, the install will happen from
|
||||
// the PostUpdate process. We do the service update process here
|
||||
// because it's possible we are updating with updater.exe without the
|
||||
// service if the service failed to apply the update. We want to update
|
||||
// the service to a newer version in that case. If we are not running
|
||||
// through the service, then MOZ_SESSION_ID will not exist.
|
||||
WCHAR *sessionIDStr = _wgetenv(L"MOZ_SESSION_ID");
|
||||
if (!sessionIDStr) {
|
||||
if (!LaunchWinPostProcess(argv[2], gSourcePath, false, NULL)) {
|
||||
LOG(("NS_main: The post update process could not be launched.\n"));
|
||||
}
|
||||
StartServiceUpdate(argc, argv);
|
||||
}
|
||||
}
|
||||
EXIT_WHEN_ELEVATED(elevatedLockFilePath, updateLockFileHandle, 0);
|
||||
#endif /* XP_WIN */
|
||||
|
|
|
@ -473,6 +473,7 @@ MAKEFILES_xulapp="
|
|||
toolkit/components/filepicker/Makefile
|
||||
toolkit/components/find/Makefile
|
||||
toolkit/components/intl/Makefile
|
||||
toolkit/components/maintenanceservice/Makefile
|
||||
toolkit/components/microformats/Makefile
|
||||
toolkit/components/parentalcontrols/Makefile
|
||||
toolkit/components/passwordmgr/Makefile
|
||||
|
|
|
@ -137,7 +137,12 @@ WriteConsoleLog();
|
|||
|
||||
#ifdef XP_WIN
|
||||
BOOL
|
||||
WinLaunchChild(const PRUnichar *exePath, int argc, char **argv);
|
||||
WinLaunchChild(const PRUnichar *exePath, int argc,
|
||||
char **argv, HANDLE userToken = NULL);
|
||||
BOOL
|
||||
WinLaunchServiceCommand(const PRUnichar *exePath, int argc, char **argv);
|
||||
BOOL
|
||||
WriteStatusPending(LPCWSTR updateDirPath);
|
||||
#endif
|
||||
|
||||
#define NS_NATIVEAPPSUPPORT_CONTRACTID "@mozilla.org/toolkit/native-app-support;1"
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
* Ben Turner <mozilla@songbirdnest.com>
|
||||
* Robert Strong <robert.bugzilla@gmail.com>
|
||||
* Josh Aas <josh@mozilla.com>
|
||||
* Brian R. Bondy <netzen@gmail.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
|
@ -190,7 +191,7 @@ GetStatusFile(nsIFile *dir, nsCOMPtr<nsILocalFile> &result)
|
|||
}
|
||||
|
||||
static bool
|
||||
IsPending(nsILocalFile *statusFile)
|
||||
IsPending(nsILocalFile *statusFile, bool &isPendingService)
|
||||
{
|
||||
PRFileDesc *fd = nsnull;
|
||||
nsresult rv = statusFile->OpenNSPRFileDesc(PR_RDONLY, 0660, &fd);
|
||||
|
@ -205,14 +206,23 @@ IsPending(nsILocalFile *statusFile)
|
|||
return false;
|
||||
|
||||
const char kPending[] = "pending";
|
||||
return (strncmp(buf, kPending, sizeof(kPending) - 1) == 0);
|
||||
bool isPending = (strncmp(buf, kPending, sizeof(kPending) - 1) == 0);
|
||||
|
||||
const char kPendingService[] = "pending-service";
|
||||
isPendingService = (strncmp(buf, kPendingService,
|
||||
sizeof(kPendingService) - 1) == 0);
|
||||
|
||||
return isPending || isPendingService;
|
||||
}
|
||||
|
||||
static bool
|
||||
SetStatusApplying(nsILocalFile *statusFile)
|
||||
{
|
||||
PRFileDesc *fd = nsnull;
|
||||
nsresult rv = statusFile->OpenNSPRFileDesc(PR_WRONLY, 0660, &fd);
|
||||
nsresult rv = statusFile->OpenNSPRFileDesc(PR_WRONLY |
|
||||
PR_TRUNCATE |
|
||||
PR_CREATE_FILE,
|
||||
0660, &fd);
|
||||
if (NS_FAILED(rv))
|
||||
return false;
|
||||
|
||||
|
@ -334,7 +344,7 @@ CopyUpdaterIntoUpdateDir(nsIFile *greDir, nsIFile *appDir, nsIFile *updateDir,
|
|||
|
||||
static void
|
||||
ApplyUpdate(nsIFile *greDir, nsIFile *updateDir, nsILocalFile *statusFile,
|
||||
nsIFile *appDir, int appArgc, char **appArgv)
|
||||
nsIFile *appDir, int appArgc, char **appArgv, bool isPendingService)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
|
@ -480,8 +490,42 @@ ApplyUpdate(nsIFile *greDir, nsIFile *updateDir, nsILocalFile *statusFile,
|
|||
#if defined(USE_EXECV)
|
||||
execv(updaterPath.get(), argv);
|
||||
#elif defined(XP_WIN)
|
||||
if (!WinLaunchChild(updaterPathW.get(), argc, argv))
|
||||
return;
|
||||
|
||||
#ifndef MOZ_MAINTENANCE_SERVICE
|
||||
// We never want the service to be used unless we have Firefox
|
||||
isPendingService = false;
|
||||
#endif
|
||||
|
||||
if (isPendingService) {
|
||||
// Make sure the service isn't already busy processing another work item.
|
||||
SetLastError(ERROR_SUCCESS);
|
||||
HANDLE serviceRunningEvent =
|
||||
OpenEvent(EVENT_ALL_ACCESS,
|
||||
FALSE,
|
||||
L"Global\\moz-5b780de9-065b-4341-a04f-ddd94b3723e5");
|
||||
// Only use the service if we know the event exists.
|
||||
// If we have a non NULL handle, or if ERROR_ACCESS_DENIED is returned,
|
||||
// then the event exists.
|
||||
isPendingService = !serviceRunningEvent &&
|
||||
GetLastError() != ERROR_ACCESS_DENIED;
|
||||
if (serviceRunningEvent) {
|
||||
CloseHandle(serviceRunningEvent);
|
||||
}
|
||||
}
|
||||
|
||||
// Launch the update operation using the service if the status file said so.
|
||||
// We also set the status to pending to ensure we never attempt to use the
|
||||
// service more than once in a row for a single update.
|
||||
if (!isPendingService ||
|
||||
!WriteStatusPending(NS_ConvertUTF8toUTF16(updateDirPath).get()) ||
|
||||
!WinLaunchServiceCommand(updaterPathW.get(), argc, argv)) {
|
||||
// Launch the update using updater.exe
|
||||
if (!WinLaunchChild(updaterPathW.get(), argc, argv)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// We are going to process an update so we should exit now
|
||||
_exit(0);
|
||||
#elif defined(XP_MACOSX)
|
||||
CommandLineServiceMac::SetupMacCommandLine(argc, argv, true);
|
||||
|
@ -516,7 +560,9 @@ ProcessUpdates(nsIFile *greDir, nsIFile *appDir, nsIFile *updRootDir,
|
|||
return rv;
|
||||
|
||||
nsCOMPtr<nsILocalFile> statusFile;
|
||||
if (GetStatusFile(updatesDir, statusFile) && IsPending(statusFile)) {
|
||||
bool isPendingService;
|
||||
if (GetStatusFile(updatesDir, statusFile) &&
|
||||
IsPending(statusFile, isPendingService)) {
|
||||
nsCOMPtr<nsILocalFile> versionFile;
|
||||
nsCOMPtr<nsILocalFile> channelChangeFile;
|
||||
// Remove the update if the update application version file doesn't exist
|
||||
|
@ -527,7 +573,8 @@ ProcessUpdates(nsIFile *greDir, nsIFile *appDir, nsIFile *updRootDir,
|
|||
IsOlderVersion(versionFile, appVersion))) {
|
||||
updatesDir->Remove(true);
|
||||
} else {
|
||||
ApplyUpdate(greDir, updatesDir, statusFile, appDir, argc, argv);
|
||||
ApplyUpdate(greDir, updatesDir, statusFile, appDir,
|
||||
argc, argv, isPendingService);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
*
|
||||
* Contributor(s):
|
||||
* Robert Strong <robert.bugzilla@gmail.com>
|
||||
* Brian R. Bondy <netzen@gmail.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
|
@ -46,8 +47,19 @@
|
|||
#endif
|
||||
|
||||
#include "nsUTF8Utils.h"
|
||||
#include "nsWindowsHelpers.h"
|
||||
|
||||
#include <shellapi.h>
|
||||
#include <shlwapi.h>
|
||||
#include <shlobj.h>
|
||||
#include <stdio.h>
|
||||
#include <wchar.h>
|
||||
#include <rpc.h>
|
||||
#include <userenv.h>
|
||||
|
||||
#pragma comment(lib, "shlwapi.lib")
|
||||
#pragma comment(lib, "rpcrt4.lib")
|
||||
#pragma comment(lib, "userenv.lib")
|
||||
|
||||
#ifndef ERROR_ELEVATION_REQUIRED
|
||||
#define ERROR_ELEVATION_REQUIRED 740L
|
||||
|
@ -162,7 +174,7 @@ static PRUnichar* ArgToString(PRUnichar *d, const PRUnichar *s)
|
|||
*
|
||||
* argv is UTF8
|
||||
*/
|
||||
static PRUnichar*
|
||||
PRUnichar*
|
||||
MakeCommandLine(int argc, PRUnichar **argv)
|
||||
{
|
||||
int i;
|
||||
|
@ -225,16 +237,291 @@ FreeAllocStrings(int argc, PRUnichar **argv)
|
|||
}
|
||||
|
||||
/**
|
||||
* Launch a child process with the specified arguments.
|
||||
* @note argv[0] is ignored
|
||||
* @note The form of this function that takes char **argv expects UTF-8
|
||||
* Determines if the maintenance service is running or not.
|
||||
*
|
||||
* @return TRUE if the maintenance service is running.
|
||||
*/
|
||||
BOOL
|
||||
EnsureWindowsServiceRunning() {
|
||||
// Get a handle to the SCM database.
|
||||
nsAutoServiceHandle serviceManager(OpenSCManager(NULL, NULL,
|
||||
SC_MANAGER_CONNECT |
|
||||
SC_MANAGER_ENUMERATE_SERVICE));
|
||||
if (!serviceManager) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Get a handle to the service.
|
||||
nsAutoServiceHandle service(OpenServiceW(serviceManager,
|
||||
L"MozillaMaintenance",
|
||||
SERVICE_QUERY_STATUS | SERVICE_START));
|
||||
if (!service) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Make sure the service is not stopped.
|
||||
SERVICE_STATUS_PROCESS ssp;
|
||||
DWORD bytesNeeded;
|
||||
if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
|
||||
sizeof(SERVICE_STATUS_PROCESS), &bytesNeeded)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (ssp.dwCurrentState == SERVICE_STOPPED) {
|
||||
if (!StartService(service, 0, NULL)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Make sure we can get into a started state without waiting too long.
|
||||
// This usually starts instantly but the extra code is just in case it
|
||||
// takes longer.
|
||||
DWORD totalWaitTime = 0;
|
||||
static const int maxWaitTime = 1000 * 5; // Never wait more than 5 seconds
|
||||
while (QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
|
||||
sizeof(SERVICE_STATUS_PROCESS), &bytesNeeded)) {
|
||||
if (ssp.dwCurrentState == SERVICE_RUNNING) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (ssp.dwCurrentState == SERVICE_START_PENDING &&
|
||||
totalWaitTime > maxWaitTime) {
|
||||
// We will probably eventually start, but we can't wait any longer.
|
||||
break;
|
||||
}
|
||||
|
||||
if (ssp.dwCurrentState != SERVICE_START_PENDING) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Sleep(ssp.dwWaitHint);
|
||||
// Increment by at least 10 milliseconds to ensure we always make
|
||||
// progress towards maxWaitTime in case dwWaitHint is 0.
|
||||
totalWaitTime += (ssp.dwWaitHint + 10);
|
||||
}
|
||||
}
|
||||
|
||||
return ssp.dwCurrentState == SERVICE_RUNNING;
|
||||
}
|
||||
|
||||
/**
|
||||
* Joins a base directory path with a filename.
|
||||
*
|
||||
* @param base The base directory path of size MAX_PATH + 1
|
||||
* @param extra The filename to append
|
||||
* @return TRUE if the file name was successful appended to base
|
||||
*/
|
||||
|
||||
BOOL
|
||||
WinLaunchChild(const PRUnichar *exePath, int argc, PRUnichar **argv);
|
||||
PathAppendSafe(LPWSTR base, LPCWSTR extra)
|
||||
{
|
||||
if (wcslen(base) + wcslen(extra) >= MAX_PATH) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return PathAppendW(base, extra);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains the directory path to store work item files.
|
||||
*
|
||||
* @return TRUE if the path was obtained successfully.
|
||||
*/
|
||||
BOOL
|
||||
WinLaunchChild(const PRUnichar *exePath, int argc, char **argv)
|
||||
GetUpdateDirectoryPath(PRUnichar *path)
|
||||
{
|
||||
HRESULT hr = SHGetFolderPathW(NULL, CSIDL_COMMON_APPDATA, NULL,
|
||||
SHGFP_TYPE_CURRENT, path);
|
||||
if (FAILED(hr)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!PathAppendSafe(path, L"Mozilla")) {
|
||||
return FALSE;
|
||||
}
|
||||
// The directory should already be created from the installer, but
|
||||
// just to be safe in case someone deletes.
|
||||
CreateDirectoryW(path, NULL);
|
||||
|
||||
if (!PathAppendSafe(path, L"updates")) {
|
||||
return FALSE;
|
||||
}
|
||||
CreateDirectoryW(path, NULL);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Launch a service initiated action with the specified arguments.
|
||||
*
|
||||
* @param exePath The path of the executable to run
|
||||
* @param argc The total number of arguments in argv
|
||||
* @param argv An array of null terminated strings to pass to the exePath,
|
||||
* argv[0] is ignored
|
||||
* @return TRUE if successful
|
||||
*/
|
||||
BOOL
|
||||
WinLaunchServiceCommand(const PRUnichar *exePath, int argc, PRUnichar **argv)
|
||||
{
|
||||
// Ensure the service is running, if not we should try to start it, if it is
|
||||
// not in a running state we cannot execute a service command.
|
||||
if (!EnsureWindowsServiceRunning()) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
PRUnichar updateData[MAX_PATH + 1];
|
||||
if (!GetUpdateDirectoryPath(updateData)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Get a unique filename
|
||||
PRUnichar tempFilePath[MAX_PATH + 1];
|
||||
const int USE_SYSTEM_TIME = 0;
|
||||
if (!GetTempFileNameW(updateData, L"moz", USE_SYSTEM_TIME, tempFilePath)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
const int FILE_SHARE_NONE = 0;
|
||||
nsAutoHandle updateMetaFile(CreateFileW(tempFilePath, GENERIC_WRITE,
|
||||
FILE_SHARE_NONE, NULL, CREATE_ALWAYS,
|
||||
0, NULL));
|
||||
if (updateMetaFile == INVALID_HANDLE_VALUE) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Write out the command ID.
|
||||
// Command ID 1 is for an update work item file, which is the only supported
|
||||
// command at this time.
|
||||
DWORD commandID = 1, commandIDWrote;
|
||||
BOOL result = WriteFile(updateMetaFile, &commandID,
|
||||
sizeof(DWORD),
|
||||
&commandIDWrote, NULL);
|
||||
|
||||
// Write out the command line arguments that are passed to updater.exe
|
||||
PRUnichar *commandLineBuffer = MakeCommandLine(argc, argv);
|
||||
DWORD sessionID, sessionIDWrote;
|
||||
ProcessIdToSessionId(GetCurrentProcessId(), &sessionID);
|
||||
result |= WriteFile(updateMetaFile, &sessionID,
|
||||
sizeof(DWORD),
|
||||
&sessionIDWrote, NULL);
|
||||
|
||||
PRUnichar appBuffer[MAX_PATH + 1];
|
||||
ZeroMemory(appBuffer, sizeof(appBuffer));
|
||||
wcscpy(appBuffer, exePath);
|
||||
DWORD appBufferWrote;
|
||||
result |= WriteFile(updateMetaFile, appBuffer,
|
||||
MAX_PATH * sizeof(PRUnichar),
|
||||
&appBufferWrote, NULL);
|
||||
|
||||
PRUnichar workingDirectory[MAX_PATH + 1];
|
||||
ZeroMemory(workingDirectory, sizeof(appBuffer));
|
||||
GetCurrentDirectoryW(sizeof(workingDirectory) / sizeof(workingDirectory[0]),
|
||||
workingDirectory);
|
||||
DWORD workingDirectoryWrote;
|
||||
result |= WriteFile(updateMetaFile, workingDirectory,
|
||||
MAX_PATH * sizeof(PRUnichar),
|
||||
&workingDirectoryWrote, NULL);
|
||||
|
||||
DWORD commandLineLength = wcslen(commandLineBuffer) * sizeof(PRUnichar);
|
||||
DWORD commandLineWrote;
|
||||
result |= WriteFile(updateMetaFile, commandLineBuffer,
|
||||
commandLineLength,
|
||||
&commandLineWrote, NULL);
|
||||
free(commandLineBuffer);
|
||||
if (!result ||
|
||||
sessionIDWrote != sizeof(DWORD) ||
|
||||
commandIDWrote != sizeof(DWORD) ||
|
||||
appBufferWrote != MAX_PATH * sizeof(PRUnichar) ||
|
||||
workingDirectoryWrote != MAX_PATH * sizeof(PRUnichar) ||
|
||||
commandLineWrote != commandLineLength) {
|
||||
updateMetaFile.reset();
|
||||
DeleteFileW(tempFilePath);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Note we construct the 'service work' meta object with a .tmp extension,
|
||||
// When we want the service to start processing it we simply rename it to
|
||||
// have a .mz extension. This ensures that the service will never try to
|
||||
// process a partial update work meta file.
|
||||
updateMetaFile.reset();
|
||||
PRUnichar completedMetaFilePath[MAX_PATH + 1];
|
||||
wcscpy(completedMetaFilePath, tempFilePath);
|
||||
|
||||
// Change the file extension of the temp file path from .tmp to .mz
|
||||
LPWSTR extensionPart =
|
||||
&(completedMetaFilePath[wcslen(completedMetaFilePath) - 3]);
|
||||
wcscpy(extensionPart, L"mz");
|
||||
return MoveFileExW(tempFilePath, completedMetaFilePath,
|
||||
MOVEFILE_REPLACE_EXISTING);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets update.status to pending so that the next startup will not use
|
||||
* the service and instead will attempt an update the with a UAC prompt.
|
||||
*
|
||||
* @param updateDirPath The path of the update directory
|
||||
* @return TRUE if successful
|
||||
*/
|
||||
BOOL
|
||||
WriteStatusPending(LPCWSTR updateDirPath)
|
||||
{
|
||||
PRUnichar updateStatusFilePath[MAX_PATH + 1];
|
||||
wcscpy(updateStatusFilePath, updateDirPath);
|
||||
if (!PathAppendSafe(updateStatusFilePath, L"update.status")) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
const char pending[] = "pending";
|
||||
nsAutoHandle statusFile(CreateFileW(updateStatusFilePath, GENERIC_WRITE, 0,
|
||||
NULL, CREATE_ALWAYS, 0, NULL));
|
||||
if (statusFile == INVALID_HANDLE_VALUE) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
DWORD wrote;
|
||||
BOOL ok = WriteFile(statusFile, pending,
|
||||
sizeof(pending) - 1, &wrote, NULL);
|
||||
return ok && (wrote == sizeof(pending) - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets update.status to a specific failure code
|
||||
*
|
||||
* @param updateDirPath The path of the update directory
|
||||
* @return TRUE if successful
|
||||
*/
|
||||
BOOL
|
||||
WriteStatusFailure(LPCWSTR updateDirPath, int errorCode)
|
||||
{
|
||||
PRUnichar updateStatusFilePath[MAX_PATH + 1];
|
||||
wcscpy(updateStatusFilePath, updateDirPath);
|
||||
if (!PathAppendSafe(updateStatusFilePath, L"update.status")) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
nsAutoHandle statusFile(CreateFileW(updateStatusFilePath, GENERIC_WRITE, 0,
|
||||
NULL, CREATE_ALWAYS, 0, NULL));
|
||||
if (statusFile == INVALID_HANDLE_VALUE) {
|
||||
return FALSE;
|
||||
}
|
||||
char failure[32];
|
||||
sprintf(failure, "failed: %d", errorCode);
|
||||
|
||||
DWORD toWrite = strlen(failure);
|
||||
DWORD wrote;
|
||||
BOOL ok = WriteFile(statusFile, failure,
|
||||
toWrite, &wrote, NULL);
|
||||
return ok && wrote == toWrite;
|
||||
}
|
||||
|
||||
/**
|
||||
* Launch a service initiated action with the specified arguments.
|
||||
*
|
||||
* @param exePath The path of the executable to run
|
||||
* @param argc The total number of arguments in argv
|
||||
* @param argv An array of null terminated strings to pass to the exePath,
|
||||
* argv[0] is ignored
|
||||
* @return TRUE if successful
|
||||
*/
|
||||
BOOL
|
||||
WinLaunchServiceCommand(const PRUnichar *exePath, int argc, char **argv)
|
||||
{
|
||||
PRUnichar** argvConverted = new PRUnichar*[argc];
|
||||
if (!argvConverted)
|
||||
|
@ -248,34 +535,104 @@ WinLaunchChild(const PRUnichar *exePath, int argc, char **argv)
|
|||
}
|
||||
}
|
||||
|
||||
BOOL ok = WinLaunchChild(exePath, argc, argvConverted);
|
||||
BOOL ok = WinLaunchServiceCommand(exePath, argc, argvConverted);
|
||||
FreeAllocStrings(argc, argvConverted);
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Launch a child process with the specified arguments.
|
||||
* @note argv[0] is ignored
|
||||
* @note The form of this function that takes char **argv expects UTF-8
|
||||
*/
|
||||
|
||||
BOOL
|
||||
WinLaunchChild(const PRUnichar *exePath,
|
||||
int argc, PRUnichar **argv,
|
||||
HANDLE userToken = NULL);
|
||||
|
||||
BOOL
|
||||
WinLaunchChild(const PRUnichar *exePath,
|
||||
int argc, char **argv,
|
||||
HANDLE userToken)
|
||||
{
|
||||
PRUnichar** argvConverted = new PRUnichar*[argc];
|
||||
if (!argvConverted)
|
||||
return FALSE;
|
||||
|
||||
for (int i = 0; i < argc; ++i) {
|
||||
argvConverted[i] = AllocConvertUTF8toUTF16(argv[i]);
|
||||
if (!argvConverted[i]) {
|
||||
FreeAllocStrings(i, argvConverted);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
BOOL ok = WinLaunchChild(exePath, argc, argvConverted, userToken);
|
||||
FreeAllocStrings(argc, argvConverted);
|
||||
return ok;
|
||||
}
|
||||
|
||||
BOOL
|
||||
WinLaunchChild(const PRUnichar *exePath, int argc, PRUnichar **argv)
|
||||
WinLaunchChild(const PRUnichar *exePath,
|
||||
int argc,
|
||||
PRUnichar **argv,
|
||||
HANDLE userToken)
|
||||
{
|
||||
PRUnichar *cl;
|
||||
BOOL ok;
|
||||
|
||||
cl = MakeCommandLine(argc, argv);
|
||||
if (!cl)
|
||||
if (!cl) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
STARTUPINFOW si = {sizeof(si), 0};
|
||||
STARTUPINFOW si = {0};
|
||||
si.cb = sizeof(STARTUPINFOW);
|
||||
si.lpDesktop = L"winsta0\\Default";
|
||||
PROCESS_INFORMATION pi = {0};
|
||||
|
||||
ok = CreateProcessW(exePath,
|
||||
cl,
|
||||
NULL, // no special security attributes
|
||||
NULL, // no special thread attributes
|
||||
FALSE, // don't inherit filehandles
|
||||
0, // No special process creation flags
|
||||
NULL, // inherit my environment
|
||||
NULL, // use my current directory
|
||||
&si,
|
||||
&pi);
|
||||
if (userToken == NULL) {
|
||||
ok = CreateProcessW(exePath,
|
||||
cl,
|
||||
NULL, // no special security attributes
|
||||
NULL, // no special thread attributes
|
||||
FALSE, // don't inherit filehandles
|
||||
0, // No special process creation flags
|
||||
NULL, // inherit my environment
|
||||
NULL, // use my current directory
|
||||
&si,
|
||||
&pi);
|
||||
} else {
|
||||
// Create an environment block for the process we're about to start using
|
||||
// the user's token.
|
||||
LPVOID environmentBlock = NULL;
|
||||
if (!CreateEnvironmentBlock(&environmentBlock, userToken, TRUE)) {
|
||||
environmentBlock = NULL;
|
||||
}
|
||||
|
||||
ok = CreateProcessAsUserW(userToken,
|
||||
exePath,
|
||||
cl,
|
||||
NULL, // no special security attributes
|
||||
NULL, // no special thread attributes
|
||||
FALSE, // don't inherit filehandles
|
||||
CREATE_DEFAULT_ERROR_MODE |
|
||||
#ifdef DEBUG
|
||||
CREATE_NEW_CONSOLE |
|
||||
#endif
|
||||
CREATE_UNICODE_ENVIRONMENT,
|
||||
environmentBlock,
|
||||
NULL, // use my current directory
|
||||
&si,
|
||||
&pi);
|
||||
|
||||
if (environmentBlock) {
|
||||
DestroyEnvironmentBlock(environmentBlock);
|
||||
}
|
||||
}
|
||||
|
||||
if (ok) {
|
||||
CloseHandle(pi.hProcess);
|
||||
|
@ -283,15 +640,14 @@ WinLaunchChild(const PRUnichar *exePath, int argc, PRUnichar **argv)
|
|||
} else {
|
||||
LPVOID lpMsgBuf = NULL;
|
||||
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||||
FORMAT_MESSAGE_FROM_SYSTEM |
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL,
|
||||
GetLastError(),
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
(LPTSTR) &lpMsgBuf,
|
||||
0,
|
||||
NULL
|
||||
);
|
||||
FORMAT_MESSAGE_FROM_SYSTEM |
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL,
|
||||
GetLastError(),
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
(LPTSTR) &lpMsgBuf,
|
||||
0,
|
||||
NULL);
|
||||
wprintf(L"Error restarting: %s\n", lpMsgBuf ? lpMsgBuf : L"(null)");
|
||||
if (lpMsgBuf)
|
||||
LocalFree(lpMsgBuf);
|
||||
|
@ -301,3 +657,4 @@ WinLaunchChild(const PRUnichar *exePath, int argc, PRUnichar **argv)
|
|||
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
|
|
@ -138,6 +138,12 @@ SDK_HEADERS = \
|
|||
nsCycleCollector.h \
|
||||
nsObjCExceptions.h \
|
||||
|
||||
ifeq ($(OS_ARCH),WINNT)
|
||||
SDK_HEADERS += \
|
||||
nsWindowsHelpers.h \
|
||||
$(NULL)
|
||||
endif
|
||||
|
||||
XPIDLSRCS = \
|
||||
nsIConsoleListener.idl \
|
||||
nsIConsoleMessage.idl \
|
||||
|
|
|
@ -0,0 +1,118 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is an RAII helper classes for Windows development.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Brian R. Bondy <netzen@gmail.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef nsWindowsHelpers_h
|
||||
#define nsWindowsHelpers_h
|
||||
|
||||
#include "nsAutoRef.h"
|
||||
#include "nscore.h"
|
||||
|
||||
template<>
|
||||
class nsAutoRefTraits<HKEY>
|
||||
{
|
||||
public:
|
||||
typedef HKEY RawRef;
|
||||
static HKEY Void()
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void Release(RawRef aFD)
|
||||
{
|
||||
if (aFD != Void()) {
|
||||
RegCloseKey(aFD);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
class nsAutoRefTraits<SC_HANDLE>
|
||||
{
|
||||
public:
|
||||
typedef SC_HANDLE RawRef;
|
||||
static SC_HANDLE Void()
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void Release(RawRef aFD)
|
||||
{
|
||||
if (aFD != Void()) {
|
||||
CloseServiceHandle(aFD);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
class nsSimpleRef<HANDLE>
|
||||
{
|
||||
protected:
|
||||
typedef HANDLE RawRef;
|
||||
|
||||
nsSimpleRef() : mRawRef(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
nsSimpleRef(RawRef aRawRef) : mRawRef(aRawRef)
|
||||
{
|
||||
}
|
||||
|
||||
bool HaveResource() const
|
||||
{
|
||||
return mRawRef != NULL && mRawRef != INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
public:
|
||||
RawRef get() const
|
||||
{
|
||||
return mRawRef;
|
||||
}
|
||||
|
||||
static void Release(RawRef aRawRef)
|
||||
{
|
||||
if (aRawRef != NULL && aRawRef != INVALID_HANDLE_VALUE) {
|
||||
CloseHandle(aRawRef);
|
||||
}
|
||||
}
|
||||
RawRef mRawRef;
|
||||
};
|
||||
|
||||
typedef nsAutoRef<HKEY> nsAutoRegKey;
|
||||
typedef nsAutoRef<SC_HANDLE> nsAutoServiceHandle;
|
||||
typedef nsAutoRef<HANDLE> nsAutoHandle;
|
||||
|
||||
#endif
|
|
@ -83,6 +83,9 @@ interface nsIWindowsRegKey : nsISupports
|
|||
ACCESS_CREATE_SUB_KEY;
|
||||
const unsigned long ACCESS_ALL = ACCESS_READ |
|
||||
ACCESS_WRITE;
|
||||
const unsigned long WOW64_32 = 0x00000200;
|
||||
const unsigned long WOW64_64 = 0x00000100;
|
||||
|
||||
|
||||
/**
|
||||
* Values for the type of a registry value. The numeric values of these
|
||||
|
|
Загрузка…
Ссылка в новой задаче