1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-01-10 01:48:00 +00:00
Commit Graph

5582 Commits

Author SHA1 Message Date
Simon Tatham
2a5d8e05e8 Add a TermWin method to draw a 'trust sigil'.
This is not yet used by anything, but the idea is that it'll be a
graphic in the terminal window that can't be replicated by a server
sending escape sequences, and hence can be used as a reliable
indication that the text on a particular terminal line is generated by
PuTTY itself and not passed through from the server. This will make it
possible to detect a malicious server trying to mimic local prompts to
trick you out of information that shouldn't be sent over the wire
(such as private-key passphrases).

The trust sigil I've picked is a small copy of the PuTTY icon, which
is thematically nice (it can be read as if the PuTTY icon is the name
of the speaker in a dialogue) and also convenient because we had that
graphic available already on all platforms. (Though the contortions I
had to go through to make the GTK 1 code draw it were quite annoying.)

The trust sigil has the same dimensions as a CJK double-width
character, i.e. it's 2 character cells wide by 1 high.
2019-03-16 12:25:23 +00:00
Simon Tatham
e21afff605 Move sanitisation of k-i prompts into the SSH code.
Now, instead of each seat's prompt-handling function doing the
control-char sanitisation of prompt text, the SSH code does it. This
means we can do it differently depending on the prompt.

In particular, prompts _we_ generate (e.g. a genuine request for your
private key's passphrase) are not sanitised; but prompts coming from
the server (in keyboard-interactive mode, or its more restricted SSH-1
analogues, TIS and CryptoCard) are not only sanitised but also
line-length limited and surrounded by uncounterfeitable headers, like
I've just done to the authentication banners.

This should mean that if a malicious server tries to fake the local
passphrase prompt (perhaps because it's somehow already got a copy of
your _encrypted_ private key), you can tell the difference.
2019-03-16 12:25:23 +00:00
Simon Tatham
767a9c6e45 Add a 'from_server' flag in prompts_t.
This goes with the existing 'to_server' flag (indicating whether the
values typed by the user are going to be sent over the wire or remain
local), to indicate whether the _text of the prompts_ has come over
the wire or is originated locally.

Like to_server, nothing yet uses this. It's a hedge against the
possibility of maybe having an option for all the auth prompts to work
via GUI dialog boxes.
2019-03-16 12:25:23 +00:00
Simon Tatham
530b6fed5d Anti-spoofing protection for SSH auth banners.
The banner text sent by the server was already being run through a
StripCtrlChars. Now it's run through one in line-limiting mode, and
surrounded by header and footer lines long enough that the line-length
limit wouldn't allow the server to counterfeit one. So it should now
be reliably possible to tell what is banner text sent by the server,
and what is not.
2019-03-16 12:25:23 +00:00
Simon Tatham
3936616feb Add line-length limit feature in StripCtrlChars.
Now it can optionally check that output lines don't go beyond a
certain length (measured in terminal columns, via wcwidth, rather than
bytes or characters). In this mode, lines are prefixed with a
distinctive character (namely '|'), and if a line is too long, then it
is broken and the continuation line gets a different prefix ('>').

When StripCtrlChars is targeting a terminal, it asks the terminal to
call wcwidth on its behalf, so it can be sure to use the same idea as
the real terminal about which characters are wide (i.e. depending on
the configuration of ambiguous characters).

This mode isn't yet used anywhere.
2019-03-16 12:25:23 +00:00
Simon Tatham
da1c8f15b1 Limit the number of combining chars per terminal cell.
The previous unlimited system was nicely general, but unfortunately
meant you could easily DoS a PuTTY-based terminal by sending a
printing character followed by an endless stream of identical
combining chars. (In fact, due to accidentally-quadratic linked list
management, you'd DoS it by using up all the CPU even before you got
the point of making it allocate all the RAM.)

The new limit is chosen to be 32, more or less arbitrarily. Overlong
sequences of combining characters are signalled by turning the whole
character cell into U+FFFD REPLACEMENT CHARACTER.
2019-03-16 12:25:23 +00:00
Simon Tatham
b9d0371c47 Add validation of remote keys in ECC Diffie-Hellman.
In both the Weierstrass and Montgomery forms, we now check that the
provided curve point isn't a silly one, like the identity or a torsion
point, which will give little or no variation in the possible outputs
of key exchange.
2019-03-16 12:25:23 +00:00
Simon Tatham
5fbd294c20 Add missing dh_validate_f in GSSAPI key exchange.
This checks that the public Diffie-Hellman value sent by the server is
not an obviously silly one like 1 or -1 (mod p). We already had the
validation function, and were using it in standard DH key exchange,
but the parallel code in the GSSAPI case missed it out.
2019-03-16 12:25:23 +00:00
Simon Tatham
03777723e5 Fix crash printing a width-2 char in a width-1 terminal.
If the terminal is one column wide, it's not possible to print a
double-width CJK character at all - it won't fit. Replace it with
U+FFFD to indicate that impossibility.

The previous behaviour was to notice that we're in the rightmost
column of the terminal, and invoke the LATTR_WRAPPED2 special case to
wrap to the leftmost column on the next line. But in a width-1
terminal, the rightmost column _is_ the leftmost column, so this would
leave us no better off, and we would have fallen through into the next
case while in exactly the situation we'd tried to rule out.
2019-03-16 12:25:23 +00:00
Simon Tatham
daf91ef8ae Fix crash on ESC#6 + combining chars + GTK + odd-width terminal.
When we're displaying double-width text as a result of the VT100 ESC#6
escape sequence or its friends, and the terminal width is an odd
number of columns, we divide by 2 the number of characters we'll even
try to display, and round _down_: if there's a rightmost odd column,
it stays blank, and doesn't show the left half of a double-width char.

In the GTK redraw function, that rounding-down can set the 'len'
variable to zero. But when we're displaying a character with Unicode
combining chars on top, that fails an assertion that len == 1, because
at the top of the function we set it to 1.

The fix is just to return early if len is reduced to zero by that
rounding: if we're not displaying any characters, then we don't have
to do anything at all.
2019-03-16 12:25:23 +00:00
Simon Tatham
3edc1b330d Disallow REP escape sequence with no prior graphic char.
The REP escape (ESC [ nnn b) causes the previously printed graphic
character to be repeated another nnn times. So if it's sent as the
very first thing in a terminal session, when there _is_ no previously
printed graphic character, there's nothing sensible it can do.

In fact, in that situation, it does something decidedly _not_
sensible: it takes the uninitialised value term->last_graphic_char and
sends it directly to term_display_graphic_char, with undesirable
results if it's not actually a printing character. In particular, the
value 0 is treated as a combining char (because it has zero wcwidth),
leading to a knock-on assertion failure when compressing the
scrollback lines (which uses \0 as a terminating value for sequences
of combining characters, precisely because it expects it never to show
up in an actual cc slot!).
2019-03-16 12:25:23 +00:00
Simon Tatham
d828549995 RSA kex: enforce the minimum key length.
I completely forgot to check that the server had actually sent a key
of at least MINKLEN bits, as RFC 4432 clearly says that it MUST.
Without this restriction, not only can a server trick the client into
using a shared secret with inadequate entropy, but it can send a key
so short that the client attempts to generate a secret integer of
negative length, with integer-overflowing results.
2019-03-16 12:25:23 +00:00
Simon Tatham
5c926d9ea4 Switch to using poll(2) in place of select(2).
I've always thought poll was more hassle to set up, because if you
want to reuse part of your pollfds list between calls then you have to
index every fd by its position in the list as well as the fd number
itself, which gives you twice as many indices to keep track of than if
the fd is always its own key.

But the problem is that select is fundamentally limited to the range
of fds that can fit in an fd_set, which is not the range of fds that
can _exist_, so I've had a change of heart and now have to go with
poll.

For the moment, I've surrounded it with a 'pollwrapper' structure that
lets me treat it more or less like select, containing a tree234 that
maps each fd to its location in the list, and also translating between
the simple select r/w/x classification and the richer poll flags.
That's let me do the migration with minimal disruption to the call
sites.

In future perhaps I can start using poll more directly, and/or using
the richer flag system (though the latter might be fiddly because of
sometimes being constrained to use the glib event loop). But this will
do for now.
2019-03-16 12:25:23 +00:00
Simon Tatham
47202c4e16 Introduce an enum of the uxsel / select_result flags.
Those magic numbers 1,2,4 were getting annoying. Time to replace them
while I can still remember what they do.
2019-03-16 12:25:23 +00:00
Simon Tatham
9f0e0b02e3 Include the installer versions of binaries in checksum files.
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.
2019-03-16 12:25:23 +00:00
Jacob Nevins
8b7458119f Tweak version string resources for EMBED_CHM.
So that it's possible to distinguish the CHMful from the CHMless binary
without running it.
2019-03-16 12:25:23 +00:00
Jacob Nevins
a8d3008143 Stop shipping old WinHelp (.HLP) file.
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.
2019-03-16 12:25:23 +00:00
Simon Tatham
67d3791de8 Stop looking for putty.chm alongside the binary.
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.
2019-03-16 12:25:23 +00:00
Simon Tatham
63a58759b5 Sanity-check the 'Public-Lines' field in ppk files.
If it's too large, memory allocation can fail, or worse,
under-allocate due to integer overflow.
2019-03-16 12:25:23 +00:00
Jacob Nevins
baa04337a4 Make 'scctest' compile according to instructions. 2019-03-16 12:12:34 +00:00
Jacob Nevins
adce412122 Rewrite faq-server to acknowledge Uppity. 2019-03-16 00:03:25 +00:00
Jacob Nevins
2795643932 Briefly acknowledge Authenticode on Keys page. 2019-03-15 23:15:07 +00:00
Simon Tatham
f098dc748d Fix build failures under GTK 1.
My previous dodge to make the GTK 1 headers work with modern compilers
was to manually reset to -std=gnu89, which changed the semantics of
'inline' back to what glib.h was expecting. But that doesn't work now
the PuTTY code base expects to be able to use the rest of C99, so
instead I have to manually override the specific #defines that glib.h
uses to know how 'inline' works.

Also, moved that code in configure.ac out of the fallback branch that
manually detects GTK1, so that it will fire even if autoconf is run on
a system that still has the genuine GTK1 detection code. (Amazingly,
one still exists that I have access to!)

With that fixed, there's one more problem: the nethack_mode and
app_keypad_mode flags in gtkwin.c's key_event() are only used in the
GTK >= 2 branch of the ifdefs, so they should only be declared and set
in that branch as well, on pain of a -Wunused complaint.
2019-03-12 08:06:20 +00:00
Simon Tatham
ba91e4b996 Avoid multiply defining {HIGH,LOW}_SURROGATE_{START,END}.
A user reports that under OpenWatcom these are defined in <winnls.h>,
in which case it's redundant to redefine them ourselves and provokes a
compiler diagnostic.
2019-03-11 19:07:18 +00:00
Simon Tatham
804ac21381 Check the return value from ssh2_transport_filter_queue!
I carefully made it return a bool to indicate that the whole PPL had
been freed, and then never actually checked that return value, so any
kind of connection-fatal event inside filter_queue (such as reporting
a DISCONNECT message) would cause a reference to freed memory on
return.
2019-03-10 19:27:20 +00:00
Simon Tatham
58fd58d64c Fix crash if the SSH server disconnects.
When ssh_remote_error returns, the ssh2_transport_state has been
freed, so we shouldn't try to reach into it to pop its in_pq.
2019-03-10 19:27:20 +00:00
Simon Tatham
a1ce240cfb ssh2bpp: try to report DISCONNECT before connection closure.
There was a race between toplevel callbacks: if we read enough data to
receive an SSH_MSG_DISCONNECT, and then returned, then whether we
reported the DISCONNECT message or the followup EOF would depend on
whether the BPP or the master PPL got called back first. Now the BPP
politely waits its turn (i.e. waits to see if it even gets called back
at all) before reporting EOF.
2019-03-10 19:27:20 +00:00
Simon Tatham
e4e309e5a4 clear_line(): replace size check with a resize.
Turns out that my assertion that term->cols == line->cols can
sometimes fail, because if the window is shrunk, scrlineptr()
deliberately _doesn't_ shrink the line (so that the columns on the
right can be recovered if the window is then resized larger again). So
clear_line() should _make_ the line the right width, instead of
asserting that it already is.
2019-03-10 19:27:20 +00:00
Simon Tatham
5ca340cf1d terminal.c: some minor refactorings (NFC).
I've factored out clear_line() (wipe out everything on a terminal line
including its line attrs) and also line_cols() (determine how many
columns are on this particular line, taking into account
LATTR_WRAPPED2 which reduces it by one).

Also, newline() and freeline() were badly named. Now they're called
newtermline() and freetermline(), which include the full actual type
name they deal with, and also means that now neither of them is named
the same as a control character!
2019-03-10 15:16:08 +00:00
Simon Tatham
d05d2e259f Revise the API for seat_stripctrl_new.
Now instead of taking raw arguments to configure the output
StripCtrlChars with, it takes an enumerated value giving the context
of what's being sanitised, and allows the seat to decide what the
output parameters for that context should be.

The only context currently used is SIC_BANNER (SSH login banners).
I've also added a not-yet-used one for keyboard-interactive prompts.
2019-03-09 16:43:41 +00:00
Simon Tatham
d049f0ab6c Make stripctrl_string take an existing StripCtrlChars.
Now instead of making a StripCtrlChars just for that function call, it
uses an existing one, pointing it at the output strbuf via
stripctrl_retarget.

This adds flexibility (now you can use the same convenient string-
sanitising function with a StripCtrl configured in any way you like)
and also saves pointless setting-up and tearing-down of identical sccs
all the time.

The existing call sites in PSCP and PSFTP now use a static
StripCtrlChars instance that was made at program startup.
2019-03-09 16:21:49 +00:00
Simon Tatham
cfef137ea2 StripCtrlChars: retarget and reset functions.
stripctrl_retarget() points the StripCtrlChars at a new BinarySink, to
avoid having to pointlessly throw it away and make a new one all the
time.

Since that probably means the same scc is going to be reused for
processing a fresh data stream, we also don't want any character-set
conversion state hanging over from the previous stream, so we also
reset the state in the process. Just in case it's needed,
stripctrl_reset() is also provided to do that operation on its own.
2019-03-09 16:21:49 +00:00
Simon Tatham
d62a369af8 PSCP, PSFTP: don't duplicate slashes in dir_file_cat.
Now if a pathname ends with a slash already, we detect that (using the
shiny new ptrlen_endswith), and don't bother putting another one in.

No functional change, but this should improve the occasional error
message, e.g. 'pscp remote:some.filename /' will now say it can't
create /some.filename instead of //some.filename.
2019-03-09 16:21:49 +00:00
Simon Tatham
757c91e2de Extra ptrlen function, ptrlen_endswith().
Identical to ptrlen_startswith(), only the other way round.
2019-03-09 16:21:49 +00:00
Simon Tatham
5eb6c19047 Extra inline helpers seat_{stdout,stderr}_pl.
These take a ptrlen in place of separate buffer and length arguments.
Switched over to them in lots of places.
2019-03-09 16:21:49 +00:00
Simon Tatham
71a3e7da9e host_strduptrim: support RFC 4007 address literals.
I'd never even heard of these before. We don't need to do anything
unusual with these when passing them to our own getaddrinfo, but
host_strduptrim considered them a violation of its expectations about
what an IPv6 literal looked like, and hence wasn't stripping square
brackets off one. So a port-forwarding command-line option such as
'-L 12345:[fe80::%eth0]:22' would cause the address string in the
direct-tcpip CHANNEL_OPEN packet to be "[fe80::%eth0]" instead of the
correct "fe80::%eth0", leading to getaddrinfo failure on the SSH
server side.
2019-03-09 08:13:25 +00:00
Simon Tatham
d2ddb2fdf4 Remove obsolete sanitise_term_data().
The previous commit removed its last use, so now we can garbage-
collect it, including its long-standing FIXME comment which is now
fulfilled by the new StripCtrlChars system.
2019-03-06 20:31:26 +00:00
Simon Tatham
7b48922761 Switch console prompt sanitisation to use StripCtrlChars.
Local functions in uxcons.c and wincons.c were calling the old
simplistic sanitise_term_data to print console-based prompts. Now they
use the same new system as everything else.

This removes the last use of the ASCII-centric sanitise_term_data.
2019-03-06 20:31:26 +00:00
Simon Tatham
b9c74e84dc Use StripCtrlChars to sanitise the SSH banner.
Now the banner can contain printable Unicode while still having escape
characters removed, in a way that works in both console and GUI
applications.

In the case of SSH banners, ssh2userauth.c does the sanitisation
itself, so it has to use the new Seat method to get an appropriately
configured StripCtrlChars.

(This wasn't an issue for the prompts_t system, because sanitisation
of prompt text is devolved to the local implementation of the prompt
system, in case a local implementation wants to present prompts in a
way that doesn't need sanitisation in any case, e.g. a dialog box.)
2019-03-06 20:31:26 +00:00
Simon Tatham
d60dcc2c82 Add a Seat vtable method to get a stripctrl.
If centralised code like the SSH implementation wants to sanitise
escape sequences out of a piece of server-provided text, it will need
to do it by making a locale-based StripCtrlChars if it's running in a
console context, or a Terminal-based one if it's in a GUI terminal-
window application.

All the other changes of behaviour needed between those two contexts
are handled by providing reconfigurable methods in the Seat vtable;
this one is no different. So now there's a new method in the Seat
vtable that will construct a StripCtrlChars appropriate to that kind
of seat. Terminal-window seats (gtkwin.c, window.c) implement it by
calling the new stripctrl_new_term(), and console ones use the locale-
based stripctrl_new().
2019-03-06 20:31:26 +00:00
Simon Tatham
36a11ef8d5 Use the new StripCtrlChars for terminal-based auth prompts.
SSH authentication prompts (passwords, passphrases and keyboard-
interactive) were previously sanitised to remove escape sequences by
the simplistic sanitise_term_data() in utils.c. Now they're fed
through the new mode of StripCtrlChars instead, which means they
should permit printable Unicode (if the terminal is in UTF-8 mode)
while still disallowing escape sequences. Hopefully this will be a
usability improvement to everyone whose login prompts are in a
language not representable in plain ASCII.
2019-03-06 20:31:26 +00:00
Simon Tatham
e74790003c StripCtrlChars: option to provide a target Terminal.
If you use the new stripctrl_new_term() to construct a StripCtrlChars
instead of the existing stripctrl_new(), then the resulting object
will align itself with the character-set configuration of the Terminal
object you point it at. (In fact, it'll reuse the same actual
translation code, courtesy of the last few refactoring commits.) So it
will interpret things as control characters precisely if that Terminal
would also have done so.

The previous locale-based sanitisation is appropriate if you're
sending the sanitised output to an OS terminal device managed outside
this process - the LC_CTYPE setting has the best chance of knowing how
that terminal device will interpret a byte stream. But I want to start
using the same sanitisation system for data intended for PuTTY's own
internal terminal emulator, in which case there's no reason why
LC_CTYPE should be expected to match that terminal's configuration,
and no reason to need it to either since we can check the internal
terminal configuration directly.

One small bodge: stripctrl_new_term() is actually a macro, which
passes in the function pointer term_translate() to the underlying real
constructor. That's just so that console-only tools can link in
stripctrl.c without acquiring a dependency on terminal.c (similarly to
how we pass random_read in to the mp_random functions).
2019-03-06 20:31:26 +00:00
Simon Tatham
511eea450a Factor out encode_utf8 from luni_send into utils.c.
I knew there had to already be a UTF-8 encoder _somewhere_ in this
code base, but it took me a while to find it! Now it's reusable in
other contexts.
2019-03-06 19:05:36 +00:00
Simon Tatham
0dcdb1b5a3 Expose term_translate outside terminal.c.
Also, instead of insisting on modifying the UTF-8 decoding state
inside the Terminal structure, it now takes a separate pointer to a
small struct containing that decode state. The idea is that if a
separate module wants to decode characters the same way the real
terminal would, it can pass its own mutable state structure, but the
same main Terminal pointer.
2019-03-06 07:11:41 +00:00
Simon Tatham
3cb846e70f Factor out term_out's character set translation.
I've moved it into a subfunction term_translate(), which I'm about to
reuse elsewhere. No functional change intended.
2019-03-06 07:11:35 +00:00
Simon Tatham
deafaa811e ssh2_try_send: don't try sending if a channel is half-open.
When ssh2_connection_filter_queue is _receiving_ messages about a
channel from the other end, it carefully checks if the channel
referred to is half-open. But we weren't exercising the same caution
before beginning to _send_ channel data, and we should, because in
that situation important fields like c->remwinsize aren't even
initialised yet.

This can come up, for example, due to typeahead in the main session
window before the server has sent OPEN_CONFIRMATION.
2019-03-03 07:09:26 +00:00
Simon Tatham
8c366766ae ssh.c: add a missing delete_callbacks_for_context.
If an Ssh structure is destroyed while its IdempotentCallback
ssh->ic_out_raw is prnding, then the latter will stay on callback.c's
list pointing at the freed memory.
2019-03-03 06:55:12 +00:00
Simon Tatham
0ceb73fb10 dupvprintf: fix signedness of return from vsnprintf.
It's defined in the C standard to return an int, not a size_t, and we
should honour that since the subsequent code checks it for <0.

A knock-on effect is that I reorganise the addends in one of the
sgrowarrays, to be extra careful about overflow when adding something
to that int.
2019-03-02 06:54:17 +00:00
Simon Tatham
bde7b6b158 Change sensitive strbufs/sgrowarrays to the new _nm version.
The _nm strategy is slower, so I don't want to just change everything
over no matter what its contents. In this pass I've tried to catch
everything that holds the _really_ sensitive things like passwords,
private keys and session keys.
2019-03-02 06:54:17 +00:00
Simon Tatham
a7abc7c867 Extra-secure versions of sgrowarray and strbuf.
These versions, distinguished by the _nm suffix on their names, avoid
using realloc to grow the array, in case it moves the block and leaves
a copy of the data in the freed memory at the old address. (The suffix
'nm' stands for 'no moving'.) Instead, the array is grown by making a
new allocation, manually copying the data over, and carefully clearing
the old block before freeing it.

(An alternative would be to give this code base its own custom heap in
which the ordinary realloc takes care about this kind of thing, but I
don't really feel like going to that much effort!)
2019-03-02 06:54:17 +00:00