Blocking PROCESS_QUERY_INFORMATION access to the process turned out to
stop screen readers like Microsoft Narrator from reading parts of the
PuTTY window like the System Menu.
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!
A user reported in January that locking down our process ACL causes
get_user_sid's call to OpenProcessToken to fail with a permissions
error. This _shouldn't_ be important, because we'll already have found
and cached the user SID before getting that far - but unfortunately
the call to get_user_sid in winnpc.c was bypassing the cache and
trying the whole process again.
This fix changes the memory ownership semantics of get_user_sid():
it's now an error to free the value it gives you, or else the *next*
call to get_user_sid() will return a stale pointer. Hence, also
removed those frees everywhere they appear.
Now all the uses of the licence text or the short copyright notice get
it from a new header "licence.h", which in turn is built by a Perl
script licence.pl invoked by mkfiles.pl, using LICENCE itself as the
source.
Hence, I can completely remove a whole section from the list of
licence locations in CHECKLST.txt :-)
(cherry picked from commit 9ddd071ec2)
Conflicts:
unix/gtkdlg.c
windows/winpgnt.c
(cherry-picker's notes: one conflict was just changed context, the
other was deleting a copy of the licence that wasn't quite the same
between branches)
This makes the About and Licence boxes copy-and-pasteable, similarly
to what I've just done on Unix.
(But unlike on the Unix side, here I haven't touched the host key
prompt dialog, because that's a standard Windows MessageBox and not
easy to mess around with. Plus, in any case, you can already hit ^C to
copy the whole text out of a MessageBox. Same goes for the PGP
fingerprints dialog.)
As a side effect, several copies of the copyright notice and licence
text have moved from .rc files into C source. I've updated
CHECKLST.txt, but they won't stay there for long.
(cherry picked from commit 2eb952ca31)
Conflicts:
windows/pageant.rc
windows/puttygen.rc
windows/win_res.rc2
(cherry-picker's notes: the conflict was just because several copies
of the licence text were deleted, and they weren't quite the same
between branches)
logevent() doesn't do printf-style formatting (though the logeventf
wrapper in ssh.c does), so if you need to format a message, it has to
be done separately with dupprintf.
(cherry picked from commit 1659cf3f14)
By default Windows processes have wide open ACLs which allow interference
by other processes running as the same user. Adjust our ACL to make this
a bit harder.
Because it's useful to protect PuTTYtel as well, carve winsecur.c into
advapi functions and wincapi.c for crypt32 functions.
(cherry picked from commit 48db456801)
Conflicts:
Recipe
(cherry-picker's note: the conflict was just some context not looking
quite the same)
make_private_security_descriptor and a new function protectprocess().
protectprocess() opens the running PuTTY process and adjusts the
Everyone and user access control entries in its ACL to deny a
selection of permissions which malicious processes running as the same
user could use to hijack PuTTY.
(cherry picked from commit aba7234bc1)
TOOLTYPE_NONNETWORK (i.e. pterm) already has "-log" (as does Unix
PuTTY), so there's no sense suppressing the synonym "-sessionlog".
Undocumented lacunae that remain:
plink accepts -sessionlog, but does nothing with it. Arguably it should.
puttytel accepts -sshlog/-sshrawlog (and happily logs e.g. Telnet
negotiation, as does PuTTY proper).
(cherry picked from commit a454399ec8)
Conflicts:
unix/uxplink.c
windows/winplink.c
(cherry-picker's notes: the conflict was only contextual, in the Plink
help output)
Now all the uses of the licence text or the short copyright notice get
it from a new header "licence.h", which in turn is built by a Perl
script licence.pl invoked by mkfiles.pl, using LICENCE itself as the
source.
Hence, I can completely remove a whole section from the list of
licence locations in CHECKLST.txt :-)
This makes the About and Licence boxes copy-and-pasteable, similarly
to what I've just done on Unix.
(But unlike on the Unix side, here I haven't touched the host key
prompt dialog, because that's a standard Windows MessageBox and not
easy to mess around with. Plus, in any case, you can already hit ^C to
copy the whole text out of a MessageBox. Same goes for the PGP
fingerprints dialog.)
As a side effect, several copies of the copyright notice and licence
text have moved from .rc files into C source. I've updated
CHECKLST.txt, but they won't stay there for long.
logevent() doesn't do printf-style formatting (though the logeventf
wrapper in ssh.c does), so if you need to format a message, it has to
be done separately with dupprintf.
By default Windows processes have wide open ACLs which allow interference
by other processes running as the same user. Adjust our ACL to make this
a bit harder.
Because it's useful to protect PuTTYtel as well, carve winsecur.c into
advapi functions and wincapi.c for crypt32 functions.
Thanks to Colin Harrison for spotting it very quickly. No thanks to
Visual Studio for only giving me a _warning_ when I prototyped a
function with four parameters and called it with five!
On both Unix and Windows, we now redirect the local proxy command's
standard error into a third pipe; data received from that pipe is
broken up at newlines and logged in the Event Log. So if the proxy
command emits any error messages in the course of failing to connect
to something, you now have a fighting chance of finding out what went
wrong.
This feature is disabled in command-line tools like PSFTP and Plink,
on the basis that in that situation it seems more likely that the user
would expect standard-error output to go to the ordinary standard
error in the ordinary way. Only GUI PuTTY catches it and logs it like
this, because it either doesn't have a standard error at all (on
Windows) or is likely to be pointing it at some completely unhelpful
session log file (under X).
I've defined a new value for the 'int type' parameter passed to
plug_log(), which proxy sockets will use to pass their backend
information on how the setup of their proxied connections are going.
I've implemented support for the new type code in all _nontrivial_
plug log functions (which, conveniently, are precisely the ones I just
refactored into backend_socket_log); the ones which just throw all
their log data away anyway will do that to the new code as well.
We use the new type code to log the DNS lookup and connection setup
for connecting to a networked proxy, and also to log the exact command
string sent down Telnet proxy connections (so the user can easily
debug mistakes in the configured format string) and the exact command
executed when spawning a local proxy process. (The latter was already
supported on Windows by a bodgy logging call taking advantage of
Windows in particular having no front end pointer; I've converted that
into a sensible use of the new plug_log facility, and done the same
thing on Unix.)
make_private_security_descriptor and a new function protectprocess().
protectprocess() opens the running PuTTY process and adjusts the
Everyone and user access control entries in its ACL to deny a
selection of permissions which malicious processes running as the same
user could use to hijack PuTTY.
TOOLTYPE_NONNETWORK (i.e. pterm) already has "-log" (as does Unix
PuTTY), so there's no sense suppressing the synonym "-sessionlog".
Undocumented lacunae that remain:
plink accepts -sessionlog, but does nothing with it. Arguably it should.
puttytel accepts -sshlog/-sshrawlog (and happily logs e.g. Telnet
negotiation, as does PuTTY proper).
This brings in the rest of the 0.66 branch, including some changes new
on master.
Conflicts:
doc/plink.but
sshrsa.c
(The conflicts were both trivial: in one, the addition of an extra
parameter to rsa2_newkey on master happened on the line next to 0.66's
addition of a check for NULL return value, and in the other, I'd got
the version number in the plink -h transcript messed up on master.)
Handles managed by winhandl.c have a 'busy' flag, which is used to
mean two things: (a) is a subthread currently blocked on this handle
so various operations in the main thread have to be deferred until it
finishes? And (b) is this handle currently one that should be returned
to the main loop to be waited for?
For HT_INPUT and HT_OUTPUT, those things are either both true or both
false, so a single flag covering both of them is fine. But HT_FOREIGN
handles have the property that they should always be waited for in the
main loop, but no subthread is blocked on them. The latter means that
operations done on them in the main thread should not be deferred; the
only such operation is cleaning them up in handle_free().
handle_free() was failing to spot this, and was deferring freeing
HT_FOREIGN handles until their subthread terminated - which of course
never happened. As a result, when a named pipe server was closed, its
actual Windows event object got destroyed, but winhandl.c still kept
passing it back to the main thread, leading to a tight loop because
MsgWaitForMultipleObjects would return ERROR_INVALID_HANDLE and never
block.
(cherry picked from commit 431f8db862)
On Windows, colons are illegal in filenames, because they're part of
the path syntax. But colons can appear in automatically constructed
log file names, if an IPv6 address is expanded from the &H placeholder.
Now we coerce any such illegal characters to '.', which is a bit of a
bodge but should at least cause a log file to be generated.
(cherry picked from commit 64ec5e03d5)
For the moment we're also retaining the old ones. Not sure when will
be the best time to get rid of those; after the next release, perhaps?
(cherry picked from commit e88b8d21f2)
We've had several reports that launching saved sessions from the
Windows 10 jump list fails; Changyu Li reports that this is because we
create those IShellLink objects with a command line string starting
with @, and in Windows 10 that causes the SetArguments method to
silently do the wrong thing.
(cherry picked from commit 8bf5c1b31f)
This is generated in response to the SendInput() Windows API call, if
that in turn is passed an KEYBDINPUT structure with KEYEVENTF_UNICODE
set. That method of input generation is used by programs such as
'WinCompose' to send an arbitrary Unicode character as if it had been
typed at the keyboard, even if the keyboard doesn't actually provide a
key for it.
Like VK_PROCESSKEY, this key code is an exception to our usual policy
of manually translating keystrokes: we handle it by calling
TranslateMessage, to get back the Unicode character it contains as a
WM_CHAR message.
(If that Unicode character in turn is outside the BMP, it may come
back as a pair of WM_CHARs in succession containing UTF-16 surrogates;
if so, that's OK, because the new Unicode WM_CHAR handler can cope.)
(cherry picked from commit 65f3500906)
This causes WM_CHAR messages sent to us to have a wParam containing a
16-bit value encoded in UTF-16, rather than an 8-bit value encoded in
the system code page.
As far as I can tell, there aren't many other knock-on effects - e.g.
you can still interact with the window using ordinary char-based API
functions such as SetWindowText, and the Windows API will do the
necessary conversions behind the scenes. However, even so, I'm half
expecting some sort of unforeseen bug to show up as a result of this.
(cherry picked from commit 67e5ceb9a8)
Commit f2e61275f introduced the use of uintptr_t, without adding an
include of <stdint.h> which is where the C standard says that type
should be defined. This didn't cause a build failure, because Visual
Studio also defines it in <stddef.h> which we do include. But a user
points out that other Windows toolchains - e.g. MinGW - don't
necessarily do the same.
I can't add an unconditional include of <stdint.h>, because the VS I
use for the current official builds doesn't have that header at all.
So I conditionalise it out for old VS; if it needs throwing out for
any other toolchain, I'll add further conditions as reports come in.
Handles managed by winhandl.c have a 'busy' flag, which is used to
mean two things: (a) is a subthread currently blocked on this handle
so various operations in the main thread have to be deferred until it
finishes? And (b) is this handle currently one that should be returned
to the main loop to be waited for?
For HT_INPUT and HT_OUTPUT, those things are either both true or both
false, so a single flag covering both of them is fine. But HT_FOREIGN
handles have the property that they should always be waited for in the
main loop, but no subthread is blocked on them. The latter means that
operations done on them in the main thread should not be deferred; the
only such operation is cleaning them up in handle_free().
handle_free() was failing to spot this, and was deferring freeing
HT_FOREIGN handles until their subthread terminated - which of course
never happened. As a result, when a named pipe server was closed, its
actual Windows event object got destroyed, but winhandl.c still kept
passing it back to the main thread, leading to a tight loop because
MsgWaitForMultipleObjects would return ERROR_INVALID_HANDLE and never
block.
If you use the new 'plink -shareexists' feature, then on Unix at least
it's possible for the upstream to receive EPIPE, because the
downstream makes a test connection and immediately closes it, so that
upstream fails to write its version string.
This looks a bit ugly in the upstream's Event Log, so I'm making a
special case: an error of 'broken pipe' type, which occurs on a socket
from a connection sharing downstream, before we've received a version
string from that downstream, is treated as an unusual kind of normal
connection termination and not logged as an error.
A Plink invocation of the form 'plink -shareexists <session>' tests
for a currently live connection-sharing upstream for the session in
question. <session> can be any syntax you'd use with Plink to make the
actual connection (a host/port number, a bare saved session name,
-load, whatever).
I envisage this being useful for things like adaptive proxying - e.g.
if you want to connect to host A which you can't route to directly,
and you might already have a connection to either of hosts B or C
which are viable proxies, then you could write a proxy shell script
which checks whether you already have an upstream for B or C and goes
via whichever one is currently active.
Testing for the upstream's existence has to be done by actually
connecting to its socket, because on Unix the mere existence of a
Unix-domain socket file doesn't guarantee that there's a process
listening to it. So we make a test connection, and then immediately
disconnect; hence, that shows up in the upstream's event log.
On Windows, colons are illegal in filenames, because they're part of
the path syntax. But colons can appear in automatically constructed
log file names, if an IPv6 address is expanded from the &H placeholder.
Now we coerce any such illegal characters to '.', which is a bit of a
bodge but should at least cause a log file to be generated.
I noticed that Unix PSCP was unwantedly renaming downloaded files
which had a backslash in their names, because pscp.c's stripslashes()
treated \ as a path component separator, since it hadn't been modified
since PSCP ran on Windows only.
It also turns out that pscp.c, psftp.c and winsftp.c all had a
stripslashes(), and they didn't all have quite the same prototype. So
now there's one in winsftp.c and one in uxsftp.c, with appropriate
OS-dependent behaviour, and the ones in pscp.c and psftp.c are gone.