Two minor memory-leak fixes on 0.74 seem not to be needed on master:
the fix in an early exit path of pageant_add_keyfile is done already
on master in a different way, and the missing sfree(fdlist) in
uxsftp.c is in code that's been completely rewritten in the uxcliloop
refactoring.
Other minor conflicts: the rework in commit b52641644905 of
ssh1login.c collided with the change from FLAG_VERBOSE to
seat_verbose(), and master and 0.74 each added an unrelated extra
field to the end of struct SshServerConfig.
We received a report that if you enable Windows 10's high-contrast
mode, the text in PuTTY's installer UI becomes invisible, because it's
displayed in the system default foreground colour against a background
of the white right-hand side of our 'msidialog.bmp' image. That's fine
when the system default fg is black, but high-contrast mode flips it
to white, and now you have white on white text, oops.
Some research in the WiX bug tracker suggests that in Windows 10 you
don't actually have to use BMP files for your installer images any
more: you can use PNG, and PNGs can be transparent. However, someone
else reported that that only works in up-to-date versions of Windows.
And in fact there's no need to go that far. A more elegant answer is
to simply not cover the whole dialog box with our background image in
the first place. I've reduced the size of the background image so that
it _only_ contains the pretty picture on the left-hand side, and omits
the big white rectangle that used to sit under the text. So now the
RHS of the dialog is not covered by any image at all, which has the
same effect as it being covered with a transparent image, except that
it doesn't require transparency support from msiexec. Either way, the
background for the text ends up being the system's default dialog-box
background, in the absence of any images or controls placed on top of
it - so when the high-contrast mode is enabled, it flips to black at
the same time as the text flips to white, and everything works as it
should.
The slight snag is that the pre-cooked WiX UI dialog specifications
let you override the background image itself, but not the Width and
Height fields in the control specifications that refer to them. So if
you just try to drop in a narrow image in the most obvious way, it
gets stretched across the whole window.
But that's not a show-stopper, because we're not 100% dependent on
getting WiX to produce exactly the right output. We already have the
technology to postprocess the MSI _after_ it comes out of WiX: we're
using it to fiddle the target-platform field for the Windows on Arm
installers. So all I had to do was to turn msiplatform.py into a more
general msifixup.py, add a second option to change the width of the
dialog background image, and run it on the x86 installers as well as
the Arm ones.
I'm getting tired of maintaining it as 2/3 compatible; 2 is on the way
out anyway and I'm losing patience. In future, if it breaks in 2, I
think I'm going to stop caring.
We received a report that if you enable Windows 10's high-contrast
mode, the text in PuTTY's installer UI becomes invisible, because it's
displayed in the system default foreground colour against a background
of the white right-hand side of our 'msidialog.bmp' image. That's fine
when the system default fg is black, but high-contrast mode flips it
to white, and now you have white on white text, oops.
Some research in the WiX bug tracker suggests that in Windows 10 you
don't actually have to use BMP files for your installer images any
more: you can use PNG, and PNGs can be transparent. However, someone
else reported that that only works in up-to-date versions of Windows.
And in fact there's no need to go that far. A more elegant answer is
to simply not cover the whole dialog box with our background image in
the first place. I've reduced the size of the background image so that
it _only_ contains the pretty picture on the left-hand side, and omits
the big white rectangle that used to sit under the text. So now the
RHS of the dialog is not covered by any image at all, which has the
same effect as it being covered with a transparent image, except that
it doesn't require transparency support from msiexec. Either way, the
background for the text ends up being the system's default dialog-box
background, in the absence of any images or controls placed on top of
it - so when the high-contrast mode is enabled, it flips to black at
the same time as the text flips to white, and everything works as it
should.
The slight snag is that the pre-cooked WiX UI dialog specifications
let you override the background image itself, but not the Width and
Height fields in the control specifications that refer to them. So if
you just try to drop in a narrow image in the most obvious way, it
gets stretched across the whole window.
But that's not a show-stopper, because we're not 100% dependent on
getting WiX to produce exactly the right output. We already have the
technology to postprocess the MSI _after_ it comes out of WiX: we're
using it to fiddle the target-platform field for the Windows on Arm
installers. So all I had to do was to turn msiplatform.py into a more
general msifixup.py, add a second option to change the width of the
dialog background image, and run it on the x86 installers as well as
the Arm ones.
Most of our makefiles use -Werror, and it seems silly not to do the
same for the Windows clang-cl builds.
The w32old build was not warning-clean, for a reason I can't do much
about: something in the VS2003 headers gives a lot of warnings about
mismatched #pragma pack push/pop between system header files. I don't
see anything much I can do about that except to squelch the warning
with -Wno-pragma-pack.
Those hashes aren't directly needed for authenticating downloaded
files (the installer itself is checksummed, which covers all the files
it will unpack from itself). But they'll surely come in useful for
other purposes sooner or later, so we should arrange to keep them
somewhere easy to find.
The executables were already ignoring it.
This is a minimal change; PUTTY.HLP can still be built, and there's
still all the context IDs lying around.
Buildscr changes are untested.
With this change, we stop expecting to find putty.chm alongside the
executable file. That was a security hazard comparable to DLL
hijacking, because of the risk that a malicious CHM file could be
dropped into the same directory as putty.exe (e.g. if someone ran
PuTTY from their browser's download dir)..
Instead, the standalone putty.exe (and other binaries needing help)
embed the proper CHM file within themselves, as a Windows resource,
and if called on to display the help then they write the file out to a
temporary location. This has the advantage that if you download and
run the standalone putty.exe then you actually _get_ help, which
previously didn't happen!
The versions of the binaries in the installer don't each contain a
copy of the help file; that would be extravagant. Instead, the
installer itself writes a registry entry pointing at the proper help
file, and the executables will look there.
Another effect of this commit is that I've withdrawn support for the
older .HLP format completely. It's now entirely outdated, and
supporting it through this security fix would have been a huge pain.
This is for sanitising output that's going to be sent to a terminal,
if you don't want it to be able to send arbitrary escape sequences and
thereby (for example) move the cursor back up to existing text on the
screen and overprint it confusingly.
It works using the standard C library: we convert to a wide-character
string and back, and then use wctype.h to spot control characters in
the intermediate form. This means its idea of the conversion character
set is locale-based rather than any of our own charset library's fixed
settings - which is what you want if the aim is to protect your local
terminal (which we assume the system locale represents accurately).
This also means that the sanitiser strips things that will _act_ as
control characters when sent to the local terminal, whether or not
they were intended as control characters by a server that might have
had a different character set in mind. Since the main aim is to
protect the local terminal rather than to faithfully replicate the
server's intention, I think that's the right criterion.
It only strips control characters at the charset-independent layer,
like backspace, carriage return and the escape character: wctype.h
classifies those as control characters, but classifies as printing all
of the more Unicode-specific controls like bidirectional overrides.
But that's enough to prevent cursor repositioning, for example.
stripctrl.c comes with a test main() of its own, which I wasn't able
to fold into testcrypt and put in the test suite because of its
dependence on the system locale - it wouldn't be guaranteed to work
the same way on different test systems anyway.
A knock-on build tweak: because you can feed data into this sanitiser
in chunks of arbitrary size, including partial multibyte chars, I had
to use mbrtowc() for the decoding, and that means that in the 'old'
Win32 builds I have to link against the Visual Studio C++ library as
well as the C library, because for some reason that's where mbrtowc
lived in VS2003.
This is a reasonably comprehensive test that exercises basically all
the functions I rewrote at the end of last year, and it's how I found
a lot of the bugs in them that I fixed earlier today.
It's written in Python, using the unittest framework, which is
convenient because that way I can cross-check Python's own large
integers against PuTTY's.
While I'm here, I've also added a few tests of higher-level crypto
primitives such as Ed25519, AES and HMAC, when I could find official
test vectors for them. I hope to add to that collection at some point,
and also add unit tests of some of the other primitives like ECDH and
RSA KEX.
The test suite is run automatically by my top-level build script, so
that I won't be able to accidentally ship anything which regresses it.
When it's run at build time, the testcrypt binary is built using both
Address and Leak Sanitiser, so anything they don't like will also
cause a test failure.
The word 'PuTTY' in the outgoing SSH version string has always
represented the name of the *SSH implementation* as opposed to the
name of the specific program containing it (for example, PSCP and
PSFTP don't announce themselves with a different banner). But I think
that a change from client to server merits a change in that
implementation name, so I'm removing the prefix "PuTTY" from the
constant string sshver[], and moving it to a parameter passed in
separately to ssh_verstring_new, so that the upcoming server can pass
in a different one.
I had previously left the platform field (in line 7 of the installer
database's SummaryInformation table) set at "x86" instead of any value
you might expect such as "Arm" or "Arm64", because I found that an MSI
file with either of the latter values was rejected by WoA's msiexec as
invalid.
It turns out this is because I _also_ needed to upgrade the installer
database schema version to a higher value than I even knew existed:
apparently the problem is that those platform fields aren't present in
the older schema. A test confirms that this works.
Unfortunately, WiX 3 doesn't actually know _how_ to write MSIs with
those platform values. But that's OK, because diffing the x86 and x64
MSIs against each other suggested that there were basically no other
changes in the database tables - so I can just generate the installer
as if for x64, and then rewrite that one field after installer
construction using GNOME msitools to take apart the binary file
structure and put it back together. (Those are the same tools I'm
using as part of my system for running WiX on Linux in the first
place.)
This commit introduces a script to do that post-hoc bodging, and calls
it from Buildscr. I've also changed over the choice of Program Files
folder for the Arm installers so that it's ProgramFiles64Folder
instead of ProgramFilesFolder - so now the Windows on Arm installer
doesn't incongruously default to installing in C:\Program Files (x86)!
There's always one - I did everything else in the build script, but
forgot to arrange for the wa32 and wa64 output subdirs to have a
.htaccess redirect from a fixed name like 'putty-arm64-installer.msi'
to whatever the real file name is in that particular build.
I expected this to be nightmarish because WiX 3 doesn't know about the
Windows on Arm platform at all. Fortunately, it turns out that it
doesn't have to: testing on a borrowed machine I find that Windows on
Arm's msiexec.exe is quite happy to take MSIs whose platform field in
the _SummaryInformation table says "Intel".
In fact, that seemed to be _all_ that my test machine would accept: I
tried taking the MSI apart with msidump, putting some other value in
there (e.g. "Arm64" or "Arm") and rebuilding it with msibuild, and all
I got was messages from msiexec saying "This installation package is
not supported by this processor type."
So in fact I just give WiX the same -arch x86 option that I give it
for the real 32-bit x86 Windows installer, but then I point it at the
Arm binaries, and that seems to produce a viable MSI. There is the
unfortunate effect that msiexec forcibly sets the default install
location to 'Program Files (x86)' no matter how I strive to make it
set it any other way, but that's only cosmetic: the programs _run_
just fine no matter which Program Files directory they're installed
into (and I know this won't be the first piece of software that
installs itself into the wrong one). Perhaps some day we can find a
way to do that part better.
On general principles of caution (and of not really wanting to force
Arm machines to emulate x86 code at all), the Arm versions of the
installers have the new DllOk=no flag, so they're pure MSI with no
embedded DLLs.
This arranges that we can build a completely pure MSI file, which
doesn't depend on any native code at install time. We don't lose much
by doing this - only the option to pop up the README file at the end
of installation, and validation of the install directory when you
select it from a file browser.
My immediate use for this is that I want to use it for installers that
will run on Windows on Arm. But it also seems to me like quite an
attractive property in its own right - no native code at all running
at install time would be an _especially_ good guarantee that that code
can't be hijacked by DLLs in the download directory. So I may yet
decide that the features we're losing are not critical to _any_
version of the MSI, and throw them out unconditionally.
When our Windows make commands were serial, 'make all cleantestprogs'
was a nice shorthand for 'first build all the binaries, then delete
the ones we don't want to ship'. Now they're using -j, that doesn't
work so well - last night's snapshot build log shows that the command
'rm -f testbn.exe' from the cleantestprogs target happened _before_
the lld-link command that created testbn.exe in the first place, so
that file got shipped into the download directory by mistake.
Easily fixed, of course - just run two separate make commands per
build directory.
Now we're building four rather than two sets of Windows binaries, the
build time has gone up rather painfully. I've just added a feature to
bob where it will invent a sensible value to use in 'make -j' and the
like, so let's start using it.
I build both 32- and 64-bit versions of the .exe files, code-sign
them, and create the same .zip file as I do for x86 Windows. I don't
yet have a method of building Arm MSI installers, though.
I have a grubby method of getting this to work without Wine, which I
intend to get round to publishing just as soon as I finish deciding
what its best shape is. But I don't want to wait for that before
starting to actually use it, because this eliminates the last trace of
Windows in the PuTTY Windows builds.
This permits me to do the binary builds via cross-compilation on
Linux, which is nice from a perspective of not having my build
environment subject to the same potential pool of Windows malware that
might be interested in infecting the resulting binaries. Also, it's
quicker to build and the code generation is noticeably better.
We've been planning to do that for a while, and this installer-builder
isn't going to work anyway in the build environment I'm about to move
everything to, so this seems like the moment.
This commit also updates the dumps of Plink's and PSCP's help output,
adding the -proxycmd option to both and the -shareexists option to
Plink.
(Or rather, _re_-adding the latter, since it was introduced in error
by commit 07af4ed10 due to a branch management error and hastily
removed again in 29e8c24f9. This time it really does match reality.)
The .htaccess written by Buildscr into the w64 directory was applying
a redirect from 'putty-installer.msi', but in fact the name by which
the website links to snapshot and prerelease installers in that
directory is 'putty-64bit-installer.msi'.
The Windows binaries, and both Windows and Unix source archives,
output from a bob build will now include the full SHA-1 of the source
git commit in their buildinfo (hence in all the About boxes and
command-line version output).
This will be occasionally useful to me at release time (there was that
one embarrassing incident where I managed not to notice that I'd made
a release build from entirely the wrong commit), but mostly, it just
seems like an obviously useful thing to put in a general buildinfo
section now that there is one.
By default the VS2015 linker produces binaries with the minimum
version fields in the PE header set to 06.00, which causes XP not to
recognise them as valid binaries at all. But there's no other reason
VS2015-built binaries _can't_ run on versions of Windows as old as XP;
so here I add the link option to set those fields to 05.01 which makes
XP like them again.
This only applies to the 32-bit build, because the VS2015 64-bit
linker refuses to lower the min version field to under 06.00.
Our Inno Setup installer is legacy as far as I'm concerned, so there's
no point in introducing a 64-bit version of it. 64-bit PuTTY users can
use the MSI from the start, and then there'll only ever have been one
kind of installer and they won't collide with one another.
The 32- and 64-bit installers may be distinguishable by their pathname
in the build output directory, but it's better to have their actual
filenames be different as well, so they don't collide in people's
download directories.
The MSI format has a fixed field for target architecture, so there's
no way to build a single MSI that can decide at install time whether
to install 32-bit or 64-bit (or both). The best you can do along those
lines, apparently, is to have two MSI files plus a bootstrap .EXE that
decides which of them to run, and as far as I'm concerned that would
just reintroduce all the same risks and annoyances that made us want
to migrate away from .EXE installers anyway.
The downside of moving to VS2015 is that its output won't run on very
old versions of Windows. It's not yet clear whether anyone still cares
about things before, say, Win2000 or WinXP, but since my build
environment still _has_ VS2003 available, it's easy enough to build
the extra set of binaries anyway just in case. (At least for now.)
The new binaries live in a build output directory 'w32old'. As with
w64, there is no installer for them; but unlike w64, I don't intend to
add one.
Now we've got VS2015 available (and thanks to a lot of 64-bit
cleanness fixing, in particular Tim Kosse's large patch series from
August 2015) we can do this fairly easily.
The new binaries are shipped in a 'w64' directory, alongside the
just-renamed 'w32'. There is no 64-bit installer (yet).
This is a big jump from the previous VS2003. It should add a little
performance (VS2015 is a better-optimising compiler), but mostly it's
groundwork for doing other useful things such as 64-bit builds and
security-related linker features.
The downside is reduced support for very old versions of Windows,
which I'll address shortly.
This change does affect the layout of the output build directory, and
will need corresponding website changes to avoid breaking links.
'x86' was a misnomer anyway, because it was really Windows-specific
rather than just x86-specific. Calling it 'w32' will make it look less
strange to add 'w64' alongside it.
Uses the BUILDDIR mechanism I added to Makefile.vc in commit
d3db17f3e.
This change is purely internal to Buildscr, and shouldn't affect the
output of a build. It paves the way to have Buildscr run multiple
Windows builds using different compilers, by putting each one in a
different subdirectory so that their outputs don't collide.
I've just upgraded my build environment to the latest Inno Setup
(apparently fixing some DLL hijacking issues), and found that the
build script doesn't run any more because the name of the output file
has changed - it used to produce Output/setup.exe, but now it produces
Output/mysetup.exe.
Rather than just fixing the build script to expect the new name, I've
explicitly specified an output filename of my own choice in putty.iss,
so that the build script should now work with versions before and
after the change.
This is a thing that the Inno Setup installer did, and that I didn't
get round to replicating when I rushed out the initial MSI in a hurry.
I've checked that this doesn't prevent unattended installation by
administrators: running 'msiexec /q /i putty-whatever.msi' as
administrator still installs silently after this change, without
popping up the README unexpectedly on anyone's desktop as a side
effect.
(I _think_ - but I'm still a long way from an MSI expert - that that's
because /q turns off the whole UI part of the MSI system, and the
loading of README is actually triggered by the transition away from
the final UI dialog box, which we now never visit in the first place.)
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!
Or, at least, potentially do so. The build script now has a slot into
which code-signing can be dropped by setting a variable in the bob
configuration to specify an appropriate command line.
The variable will typically need to point at a script wrapping the
actual signing tool, since there are lots of fiddly details
(timestamping countersignature, certificate, private key, etc) not
given on the command lines in this build script, on the basis that
they're local configuration questions for whoever is _running_ this
build script.
(cherry picked from commit d0e9630e1c)