From 5c5879b99d2a0785095a384f48a2d934e1b2d4c5 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Wed, 9 Mar 2016 20:44:19 +0000 Subject: [PATCH] New Windows installer system, using WiX to build an MSI. Mostly this is a reaction to the reports of Inno Setup having a DLL hijacking vulnerability. But also, the new installer has several other nice features that our Inno Setup one didn't provide: it can put the PuTTY install directory on PATH automatically, and it supports completely automatic and silent install/uninstall via 'msiexec /q' which should make it easier for sysadmins to roll out installation in large organisations. Also, it just seems like good sense to be using Windows's own native packaging system (or closest equivalent) rather than going it alone. (And on the developer side, I have to say I like the fact that WiX lets me pass in the version number as a set of command-line #define- equivalents, whereas for Inno Setup I had to have Buildscr apply Perl rewriting to the source file.) For the moment, I'm still building the old Inno Setup installer alongside this one, but I expect to retire it once the WiX one has survived in the wild for a while and proven itself more or less stable. I've found both MSI and WiX to be confusing and difficult technologies, so this installer has some noticeable pieces missing (e.g. retrospective reconfiguration of the installed feature set, and per-user vs systemwide installation) simply because I couldn't get them to work. I've commented the new installer source code heavily, in the hope that a passing WiX expert can give me a hand! --- Buildscr | 39 +++- sign.sh | 2 +- windows/installer.wxs | 452 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 482 insertions(+), 11 deletions(-) create mode 100644 windows/installer.wxs diff --git a/Buildscr b/Buildscr index 2a58507c..6e2bbc3b 100644 --- a/Buildscr +++ b/Buildscr @@ -80,11 +80,12 @@ ifneq "$(PRERELEASE)" "" set Autoconfver $(PRERELEASE)~pre$(Ndate).$(vcsid) ifneq "$(SNAPSHOT)" "" set Autoconfver $(Lastver)-$(Date).$(vcsid) ifeq "$(RELEASE)$(PRERELEASE)$(SNAPSHOT)" "" set Autoconfver Custom.$(Date).$(vcsid) -# Set up the filename for the Windows installer. -ifneq "$(RELEASE)" "" set Ifilename putty-$(RELEASE)-installer.exe -ifneq "$(PRERELEASE)" "" set Ifilename putty-$(PRERELEASE)-pre$(Ndate)-installer.exe -ifneq "$(SNAPSHOT)" "" set Ifilename putty-$(Date)-installer.exe -ifeq "$(RELEASE)$(PRERELEASE)$(SNAPSHOT)" "" set Ifilename putty-custom-$(Date)-installer.exe +# Set up the filename for the Windows installer (minus extension, +# which goes on later). +ifneq "$(RELEASE)" "" set Ifilename putty-$(RELEASE)-installer +ifneq "$(PRERELEASE)" "" set Ifilename putty-$(PRERELEASE)-pre$(Ndate)-installer +ifneq "$(SNAPSHOT)" "" set Ifilename putty-$(Date)-installer +ifeq "$(RELEASE)$(PRERELEASE)$(SNAPSHOT)" "" set Ifilename putty-custom-$(Date)-installer # Set up the version string for the Windows installer. ifneq "$(RELEASE)" "" set Iversion $(RELEASE) @@ -148,24 +149,41 @@ in putty/windows do perl -i~ -pe 'BEGIN{$$a=shift@ARGV;}s/^(VersionInfoVersion=) # Windowsify LICENCE, since it's going in the Windows installer. in putty do perl -i~ -pe 'y/\015//d;s/$$/\015/' LICENCE +# Some gratuitous theming for the MSI installer UI. +in putty/icons do make +in putty do convert -size 164x312 'gradient:blue-white' -distort SRT -90 -swirl 180 \( -size 329x312 canvas:white \) +append \( icons/putty-48.png -geometry +28+24 \) -composite \( icons/pscp-48.png -geometry +88+96 \) -composite \( icons/puttygen-48.png -geometry +28+168 \) -composite \( icons/pageant-48.png -geometry +88+240 \) -composite windows/msidialog.bmp +in putty do convert -size 493x58 canvas:white \( icons/putty-48.png -geometry +440+5 \) -composite windows/msibanner.bmp + delegate windows - # FIXME: Cygwin alternative? + # Build the main binaries. in putty/windows with visualstudio do/win nmake -f Makefile.vc $(Makeargs) all cleantestprogs + # Code-sign the binaries, if the local bob config provides a script # to do so. We assume here that the script accepts an -i option to # provide a 'more info' URL, and an optional -n option to provide a # program name, and that it can take multiple .exe filename # arguments and sign them all in place. ifneq "$(winsigncode)" "" in putty/windows do $(winsigncode) -i http://www.chiark.greenend.org.uk/~sgtatham/putty/ *.exe + # Ignore exit code from hhc, in favour of seeing whether the .chm # file was created. (Yuck; but hhc appears to return non-zero # exit codes on whim.) in putty/doc with htmlhelp do/win hhc putty.hhp & type putty.chm >nul + + # Build the WiX MSI installer. + in putty/windows with wix do/win candle -dWinver="$(Winver)" -dPuttytextver="$(Puttytextver)" installer.wxs && light -ext WixUIExtension -sval installer.wixobj + + # Build the old Inno Setup installer. in putty/windows with innosetup do/win iscc putty.iss - ifneq "$(winsigncode)" "" in putty/windows do $(winsigncode) -i http://www.chiark.greenend.org.uk/~sgtatham/putty/ -n "PuTTY Installer" Output/setup.exe + + # Sign the installers. + ifneq "$(winsigncode)" "" in putty/windows do $(winsigncode) -i http://www.chiark.greenend.org.uk/~sgtatham/putty/ -n "PuTTY Installer" installer.msi Output/setup.exe + + # Finished Windows builds. return putty/windows/*.exe return putty/windows/*.map return putty/doc/putty.chm + return putty/windows/installer.msi return putty/windows/Output/setup.exe enddelegate in putty/doc do make mostlyclean @@ -176,7 +194,8 @@ in putty/doc do zip puttydoc.zip *.html # Deliver the actual PuTTY release directory into a subdir `putty'. deliver putty/windows/*.exe putty/x86/$@ deliver putty/windows/putty.zip putty/x86/$@ -deliver putty/windows/Output/setup.exe putty/x86/$(Ifilename) +deliver putty/windows/installer.msi putty/x86/$(Ifilename).msi +deliver putty/windows/Output/setup.exe putty/x86/$(Ifilename).exe deliver putty/doc/puttydoc.zip putty/$@ deliver putty/doc/putty.chm putty/$@ deliver putty/doc/putty.hlp putty/$@ @@ -210,5 +229,5 @@ in-dest putty do echo "AddType application/octet-stream .chm" >> .htaccess in-dest putty do echo "AddType application/octet-stream .hlp" >> .htaccess in-dest putty do echo "AddType application/octet-stream .cnt" >> .htaccess in-dest putty do set -- putty*.tar.gz; for k in '' .gpg; do echo RedirectMatch temp '(.*/)'putty.tar.gz$$k\$$ '$$1'"$$1$$k" >> .htaccess; done -# And one in the x86 directory, providing a link for the installer. -in-dest putty/x86 do set -- putty*installer.exe; for k in '' .gpg; do echo RedirectMatch temp '(.*/)'putty-installer.exe$$k\$$ '$$1'"$$1$$k" >> .htaccess; done +# And one in the x86 directory, providing links for the installers. +in-dest putty/x86 do for ext in msi exe; do set -- putty*installer.$$ext; for k in '' .gpg; do echo RedirectMatch temp '(.*/)'putty-installer.$$ext$$k\$$ '$$1'"$$1$$k" >> .htaccess; done; done diff --git a/sign.sh b/sign.sh index ea63b4bf..88770475 100755 --- a/sign.sh +++ b/sign.sh @@ -27,7 +27,7 @@ sign() { cd "$1" echo "===== Signing with key '$keyname'" -for i in putty*src.zip putty*.tar.gz x86/*.exe x86/*.zip; do +for i in putty*src.zip putty*.tar.gz x86/*.exe x86/*.zip x86/*.msi; do sign --detach-sign "$i" "$i.gpg" done for i in md5sums sha1sums sha256sums sha512sums; do diff --git a/windows/installer.wxs b/windows/installer.wxs new file mode 100644 index 00000000..7be97778 --- /dev/null +++ b/windows/installer.wxs @@ -0,0 +1,452 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1 + "1"]]> + + 1 + + NOT Installed + Installed + + 1 + 1 + NOT WIXUI_DONTVALIDATEPATH + "1"]]> + WIXUI_DONTVALIDATEPATH OR WIXUI_INSTALLDIR_VALID="1" + 1 + 1 + + Installed + NOT Installed + 1 + + NOT Installed + Installed AND NOT PATCH + Installed AND PATCH + + 1 + + 1 + 1 + 1 + + + + + + + + + + + + + + -- 2.45.2