- Jun 23, 2021
-
-
Simon Tatham authored
Suggested by Manfred Kaiser, who also wrote most of this patch (although outlying parts, like documentation and SSH-1 support, are by me). This is a second line of defence against the kind of spoofing attacks in which a malicious or compromised SSH server rushes the client through the userauth phase of SSH without actually requiring any auth inputs (passwords or signatures or whatever), and then at the start of the connection phase it presents something like a spoof prompt, intended to be taken for part of userauth by the user but in fact with some more sinister purpose. Our existing line of defence against this is the trust sigil system, and as far as I know, that's still working. This option allows a bit of extra defence in depth: if you don't expect your SSH server to trivially accept authentication in the first place, then enabling this option will cause PuTTY to disconnect if it unexpectedly does so, without the user having to spot the presence or absence of a fiddly little sigil anywhere. Several types of authentication count as 'trivial'. The obvious one is the SSH-2 "none" method, which clients always try first so that the failure message will tell them what else they can try, and which a server can instead accept in order to authenticate you unconditionally. But there are two other ways to do it that we know of: one is to run keyboard-interactive authentication and send an empty INFO_REQUEST packet containing no actual prompts for the user, and another even weirder one is to send USERAUTH_SUCCESS in response to the user's preliminary *offer* of a public key (instead of sending the usual PK_OK to request an actual signature from the key). This new option detects all of those, by clearing the 'is_trivial_auth' flag only when we send some kind of substantive authentication response (be it a password, a k-i prompt response, a signature, or a GSSAPI token). So even if there's a further path through the userauth maze we haven't spotted, that somehow avoids sending anything substantive, this strategy should still pick it up. (cherry picked from commit 5f5c710c)
-
- Apr 19, 2021
-
-
Jacob Nevins authored
-
- Mar 27, 2021
-
-
Jacob Nevins authored
-
- Nov 25, 2020
-
-
Jacob Nevins authored
-
- Jun 14, 2020
-
-
Simon Tatham authored
Spotted by Leak Sanitiser, while I was investigating the PSFTP / proftpd issue mentioned in the previous commit (with ASan on as usual). The two very similar loops that read PSFTP commands from the interactive prompt and a batch file differed in one respect: only one of them remembered to free the command afterwards. Now I've moved the freeing code out into a subroutine that both loops can use. (cherry picked from commit bf0f323f)
-
Simon Tatham authored
I tried to do an SFTP upload through connection sharing the other day and found that pscp sent some data and then hung. Now I debug it, what seems to have happened was that we were looping in sftp_recv() waiting for an SFTP packet from the remote, but we didn't have any outstanding SFTP requests that the remote was going to reply to. Checking further, xfer_upload_ready() reported true, so we _could_ have sent something - but the logic in the upload loop had a hole through which we managed to get into 'waiting for a packet' state. I think what must have happened is that xfer_upload_ready() reported false so that we entered sftp_recv(), but then the event loop inside sftp_recv() ran a toplevel callback that made xfer_upload_ready() return true. So, the fix: sftp_recv() is our last-ditch fallback, and we always try emptying our callback queue and rechecking upload_ready before we resort to waiting for a remote packet. This not only fixes the hang I observed: it also hugely improves the upload speed. My guess is that the bug must have been preventing us from filling our outgoing request pipeline a _lot_ - but I didn't notice it until the one time the queue accidentally ended up empty, rather than just sparse enough to make transfers slow. Annoyingly, I actually considered this fix back when I was trying to fix the proftpd issue mentioned in commit cd97b7e7. I decided fixing ssh_sendbuffer() was a better idea. In fact it would have been an even better idea to do both! Oh well, better late than never. (cherry picked from commit 3a633bed)
-
- Mar 10, 2020
-
-
Simon Tatham authored
This is a sweeping change applied across the whole code base by a spot of Emacs Lisp. Now, everywhere I declare a vtable filled with function pointers (and the occasional const data member), all the members of the vtable structure are initialised by name using the '.fieldname = value' syntax introduced in C99. We were already using this syntax for a handful of things in the new key-generation progress report system, so it's not new to the code base as a whole. The advantage is that now, when a vtable only declares a subset of the available fields, I can initialise the rest to NULL or zero just by leaving them out. This is most dramatic in a couple of the outlying vtables in things like psocks (which has a ConnectionLayerVtable containing only one non-NULL method), but less dramatically, it means that the new 'flags' field in BackendVtable can be completely left out of every backend definition except for the SUPDUP one which defines it to a nonzero value. Similarly, the test_for_upstream method only used by SSH doesn't have to be mentioned in the rest of the backends; network Plugs for listening sockets don't have to explicitly null out 'receive' and 'sent', and vice versa for 'accepting', and so on. While I'm at it, I've normalised the declarations so they don't use the unnecessarily verbose 'struct' keyword. Also a handful of them weren't const; now they are.
-
Lars Brinkhoff authored
The motivation is for the SUPDUP protocol. The server may send a signal for the terminal to reset any input buffers. After this, the server will not know the state of the terminal, so it is required to send its cursor position back.
-
- Feb 25, 2020
-
-
Simon Tatham authored
I tried to do an SFTP upload through connection sharing the other day and found that pscp sent some data and then hung. Now I debug it, what seems to have happened was that we were looping in sftp_recv() waiting for an SFTP packet from the remote, but we didn't have any outstanding SFTP requests that the remote was going to reply to. Checking further, xfer_upload_ready() reported true, so we _could_ have sent something - but the logic in the upload loop had a hole through which we managed to get into 'waiting for a packet' state. I think what must have happened is that xfer_upload_ready() reported false so that we entered sftp_recv(), but then the event loop inside sftp_recv() ran a toplevel callback that made xfer_upload_ready() return true. So, the fix: sftp_recv() is our last-ditch fallback, and we always try emptying our callback queue and rechecking upload_ready before we resort to waiting for a remote packet. This not only fixes the hang I observed: it also hugely improves the upload speed. My guess is that the bug must have been preventing us from filling our outgoing request pipeline a _lot_ - but I didn't notice it until the one time the queue accidentally ended up empty, rather than just sparse enough to make transfers slow. Annoyingly, I actually considered this fix back when I was trying to fix the proftpd issue mentioned in commit cd97b7e7. I decided fixing ssh_sendbuffer() was a better idea. In fact it would have been an even better idea to do both! Oh well, better late than never.
-
- Feb 22, 2020
-
-
Simon Tatham authored
PSCP and PSFTP can only work over a protocol enough like SSH to be able to run subsystems (or at the very least a remote command, for old-style PSCP). Historically we've implemented this restriction by having them not support any protocol-selection command-line options at all, and hardwiring them to instantiating ssh_backend. This commit regularises them to be more like the rest of the tools. You can select a protocol using the appropriate command-line option, provided it's a protocol in those tools' backends[] array. And the setup code will find the BackendVtable to instantiate by the usual method of calling backend_vt_from_proto. Currently, this makes essentially no difference: those tools link in be_ssh.c, which means the only supported backend is SSH. So the effect is that now -ssh is an accepted option with no effect, instead of being rejected. But it opens the way to add other protocols that are SSH-like enough to run file transfer over.
-
- Feb 05, 2020
-
-
Simon Tatham authored
Spotted by Leak Sanitiser, while I was investigating the PSFTP / proftpd issue mentioned in the previous commit (with ASan on as usual). The two very similar loops that read PSFTP commands from the interactive prompt and a batch file differed in one respect: only one of them remembered to free the command afterwards. Now I've moved the freeing code out into a subroutine that both loops can use.
-
- Feb 02, 2020
-
-
Simon Tatham authored
In the previous trawl of this, I didn't bother with the statics in main-program modules, on the grounds that my main aim was to avoid 'library' objects (shared between multiple programs) from polluting the global namespace. But I think it's worth being more strict after all, so this commit adds 'static' to a lot more file-scope variables that aren't needed outside their own module.
-
Simon Tatham authored
Now it's no longer used, we can get rid of it, and better still, get rid of every #define PUTTY_DO_GLOBALS in the many source files that previously had them.
-
Simon Tatham authored
It's now a static in the main source file of each application that uses it, and isn't accessible from any other source file unless the main one passes it by reference. In fact, there were almost no instances of the latter: only the config-box functions in windlg.c were using 'conf' by virtue of its globalness, and it's easy to make those take it as a parameter.
-
- Jan 30, 2020
-
-
Simon Tatham authored
I haven't managed to make this one _not_ be a mutable variable, but at least it's not global across all tools any more: it lives in cmdline.c along with the code that decides what to set it to, and cmdline.c exports a query method to ask for its value.
-
Simon Tatham authored
Another ugly mutable global variable gone: now, instead of this variable being defined in cmdline.c and written to by everyone's main(), it's defined _alongside_ everyone's main() as a constant, and cmdline.c just refers to it. A bonus is that now nocmdline.c doesn't have to define it anyway for tools that don't use cmdline.c. But mostly, it didn't need to be mutable, so better for it not to be. While I'm at it, I've also fiddled with the bit flags that go in it, to define their values automatically using a list macro instead of manually specifying each one to be a different power of 2.
-
Simon Tatham authored
This is another piece of the old 2003 attempt at async agent requests. Nothing ever calls this function (in particular, the new working version of async-agent doesn't need it). Remove it completely, and all its special-window-message implementations too. (If we _were_ still using this function, then it would surely be possible to fold it into the more recently introduced general toplevel-callback system, and get rid of all this single-use special code. But we're not, so removing it completely is even easier.) In particular, this system was the only reason why Windows Plink paid any attention to its message queue. So now I can make it call plain WaitForMultipleObjects instead of MsgWaitForMultipleObjects.
-
Simon Tatham authored
It no longer has any flags in it at all, so its day is done.
-
Simon Tatham authored
This was the easiest flag to remove: nothing ever checks it at all! It was part of an abandoned early attempt to make Pageant requests asynchronous. The flag was added in commit 135abf24 (April 2003); the code that used it was #ifdef-ed out in commit 98d735fd (January 2004), and removed completely in commit f864265e (January 2017). We now have an actually working system for async agent requests on Windows, via the new named-pipe IPC. And we also have a perfectly good way to force a particular agent request to work synchronously: just pass NULL as the callback function pointer. All of that works just fine, without ever using this flag. So begone!
-
Simon Tatham authored
This is simpler than FLAG_VERBOSE: everywhere we need to check it, we have a Seat available, so we can just make it a Seat query method.
-
Simon Tatham authored
The global 'int flags' has always been an ugly feature of this code base, and I suddenly thought that perhaps it's time to start throwing it out, one flag at a time, until it's totally unused. My first target is FLAG_VERBOSE. This was usually set by cmdline.c when it saw a -v option on the program's command line, except that GUI PuTTY itself sets it unconditionally on startup. And then various bits of the code would check it in order to decide whether to print a given message. In the current system of front-end abstraction traits, there's no _one_ place that I can move it to. But there are two: every place that checked FLAG_VERBOSE has access to either a Seat or a LogPolicy. So now each of those traits has a query method for 'do I want verbose messages?'. A good effect of this is that subsidiary Seats, like the ones used in Uppity for the main SSH server module itself and the server end of shell channels, now get to have their own verbosity setting instead of inheriting the one global one. In fact I don't expect any code using those Seats to be generating any messages at all, but if that changes later, we'll have a way to control it. (Who knows, perhaps logging in Uppity might become a thing.) As part of this cleanup, I've added a new flag to cmdline_tooltype, called TOOLTYPE_NO_VERBOSE_OPTION. The unconditionally-verbose tools now set that, and it has the effect of making cmdline.c disallow -v completely. So where 'putty -v' would previously have been silently ignored ("I was already verbose"), it's now an error, reminding you that that option doesn't actually do anything. Finally, the 'default_logpolicy' provided by uxcons.c and wincons.c (with identical definitions) has had to move into a new file of its own, because now it has to ask cmdline.c for the verbosity setting as well as asking console.c for the rest of its methods. So there's a new file clicons.c which can only be included by programs that link against both cmdline.c _and_ one of the *cons.c, and I've renamed the logpolicy to reflect that.
-
- Dec 24, 2019
-
-
Simon Tatham authored
When I'm declaring a local instance of some context structure type to pass to a function which will pass it in turn to a callback, I've tended to use a declaration of the form struct context actx, *ctx = &actx; so that the outermost caller can initialise the context, and/or read out fields of it afterwards, by the same syntax 'ctx->foo' that the callback function will be using. So you get visual consistency between the two functions that share this context. It only just occurred to me that there's a much neater way to declare a context struct of this kind, which still makes 'ctx' behave like a pointer in the owning function, and doesn't need all that weird verbiage or a spare variable name: struct context ctx[1]; That's much nicer! I've switched to doing that in all existing cases I could find, and also in a couple of cases where I hadn't previously bothered to do the previous more cumbersome idiom.
-
- Oct 14, 2019
-
-
Simon Tatham authored
Up until now, it's been a variadic _function_, whose argument list consists of 'const char *' ASCIZ strings to concatenate, terminated by one containing a null pointer. Now, that function is dupcat_fn(), and it's wrapped by a C99 variadic _macro_ called dupcat(), which automatically suffixes the null-pointer terminating argument. This has three benefits. Firstly, it's just less effort at every call site. Secondly, it protects against the risk of accidentally leaving off the NULL, causing arbitrary words of stack memory to be dereferenced as char pointers. And thirdly, it protects against the more subtle risk of writing a bare 'NULL' as the terminating argument, instead of casting it explicitly to a pointer. That last one is necessary because C permits the macro NULL to expand to an integer constant such as 0, so NULL by itself may not have pointer type, and worse, it may not be marshalled in a variadic argument list in the same way as a pointer. (For example, on a 64-bit machine it might only occupy 32 bits. And yet, on another 64-bit platform, it might work just fine, so that you don't notice the mistake!) I was inspired to do this by happening to notice one of those bare NULL terminators, and thinking I'd better check if there were any more. Turned out there were quite a few. Now there are none.
-
- Sep 09, 2019
-
-
Simon Tatham authored
When I introduced the unreachable() macro in commit 0112936e, I searched the source code for assert(0) and assert(false), together with their variant form assert(0 && "explanatory text"). But I didn't search for assert(!"explanatory text"), which is the form I used to use before finding that assert(0 && "text") seemed to be preferred in other code bases. So, here's a belated replacement of all the assert(!"stuff") macros with further instances of unreachable().
-
- Sep 08, 2019
-
-
Simon Tatham authored
The number of people has been steadily increasing who read our source code with an editor that thinks tab stops are 4 spaces apart, as opposed to the traditional tty-derived 8 that the PuTTY code expects. So I've been wondering for ages about just fixing it, and switching to a spaces-only policy throughout the code. And I recently found out about 'git blame -w', which should make this change not too disruptive for the purposes of source-control archaeology; so perhaps now is the time. While I'm at it, I've also taken the opportunity to remove all the trailing spaces from source lines (on the basis that git dislikes them, and is the only thing that seems to have a strong opinion one way or the other). Apologies to anyone downstream of this code who has complicated patch sets to rebase past this change. I don't intend it to be needed again.
-
- Jul 10, 2019
-
-
Simon Tatham authored
This mitigates a borderline-DoS in which a malicious SFTP server sends a ludicrously large number of file names in response to a SFTP opendir/readdir request sequence, causing the client to buffer them all and use up all the system's memory simply so that it can produce the output in sorted order. I call it a 'borderline' DoS because it's very likely that this is the same server that you'll also trust to actually send you the _contents_ of some entire file or directory, in which case, if they want to DoS you they can do that anyway at that point and you have no way to tell a legit very large file from a bad one. So it's unclear to me that anyone would get any real advantage out of 'exploiting' this that they couldn't have got anyway by other means. That said, it may have practical benefits in the occasional case. Imagine a _legit_ gigantic directory (something like a maildir, perhaps, and perhaps stored on a server-side filesystem specialising in not choking on really huge single directories), together with a client workflow that involves listing the whole directory but then downloading only one particular file in it. For the moment, the threshold size is fixed at 8Mb of total data (counting the lengths of the file names as well as just the number of files). If that needs to become configurable later, we can always add an option.
-
- Jul 06, 2019
-
-
Simon Tatham authored
Affects command-line PuTTYgen, PSFTP, and anything running the SSH-2 userauth client layer. Tweaked version of a patch due to Tim Kosse.
-
- Mar 16, 2019
-
-
Simon Tatham authored
In terminal-based GUI applications, this is passed through to term_set_trust_status, to toggle whether lines are prefixed with the new trust sigil. In console applications, the function returns false, indicating to the backend that it should employ some other technique for spoofing protection.
-
- Mar 09, 2019
-
-
Simon Tatham authored
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.
-
- Mar 06, 2019
-
-
Simon Tatham authored
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().
-
- Feb 28, 2019
-
-
Simon Tatham authored
The idea of these is that they centralise the common idiom along the lines of if (logical_array_len >= physical_array_size) { physical_array_size = logical_array_len * 5 / 4 + 256; array = sresize(array, physical_array_size, ElementType); } which happens at a zillion call sites throughout this code base, with different random choices of the geometric factor and additive constant, sometimes forgetting them completely, and generally doing a lot of repeated work. The new macro sgrowarray(array,size,n) has the semantics: here are the array pointer and its physical size for you to modify, now please ensure that the nth element exists, so I can write into it. And sgrowarrayn(array,size,n,m) is the same except that it ensures that the array has size at least n+m (so sgrowarray is just the special case where m=1). Now that this is a single centralised implementation that will be used everywhere, I've also gone to more effort in the implementation, with careful overflow checks that would have been painful to put at all the previous call sites. This commit also switches over every use of sresize(), apart from a few where I really didn't think it would gain anything. A consequence of that is that a lot of array-size variables have to have their types changed to size_t, because the macros require that (they address-take the size to pass to the underlying function).
-
- Feb 21, 2019
-
-
Jacob Nevins authored
-
- Feb 20, 2019
-
-
Simon Tatham authored
This commit adds sanitisation to PSCP and PSFTP in the same style as I've just put it into Plink. This time, standard error is sanitised without reference to whether it's redirected (at least unless you give an override option), on the basis that where Plink is _sometimes_ an SSH transport for some other protocol, PSCP and PSFTP _always_ are. But also, the sanitiser is run over any remote filename sent by the server, substituting ? for any control characters it finds. That removes another avenue for the server to deliberately confuse the display. This commit fixes our bug 'pscp-unsanitised-server-output', aka the two notional 'vulnerabilities' CVE-2019-6109 and CVE-2019-6110. (Although we regard those in isolation as only bugs, not serious vulnerabilities, because their main threat was in hiding the evidence of a server having exploited other more serious vulns that we never had.)
-
- Feb 06, 2019
-
-
Simon Tatham authored
This is a general cleanup which has been overdue for some time: lots of length fields are now the machine word type rather than the (in practice) fixed 'int'.
-
Simon Tatham authored
plug_receive(), sftp_senddata() and handle_gotdata() in particular now take const pointers. Also fixed 'char *receive_data' in struct ProxySocket.
-
- Jan 04, 2019
-
-
Simon Tatham authored
I noticed a few of these in the course of preparing the previous commit. I must have been writing that idiom out by hand for _ages_ before it became totally habitual to #define it as 'lenof' in every codebase I touch. Now I've gone through and replaced all the old verbosity with nice terse lenofs.
-
- Dec 27, 2018
-
-
Simon Tatham authored
A user points out that the call to close_directory() in pscp.c's rsource() function should have been inside rather than outside the if statement that checks whether the directory handle is NULL. As a result, any failed attempt to open a directory during a 'pscp -r' recursive upload leads to a null-pointer dereference. Moved the close_directory call to where it should be, and also arranged to print the OS error code if the directory-open fails, by also changing the API of open_directory to return an error string on failure.
-
- Dec 01, 2018
-
-
Simon Tatham authored
It hasn't been possible for canonify() to return a null pointer since commit 094dd30d, in 2001. But the whole of psftp.c is full of error checking clauses that allow for the possibility that it might!
-
Simon Tatham authored
The ad-hoc code that received data from the SCP or SFTP server predated even not-very-modern conveniences such as bufchain, and was quite horrible and cumbersome. Particularly nasty was the part where ssh_scp_recv set a _global_ pointer variable to the buffer it was in the middle of writing to, and then recursed and expected a callback to use that pointer. That caused clang-analyzer to grumble at me, in a particular case where the output buffer was in the ultimate caller's stack frame; even though I'm confident the code _worked_, I can't blame clang for being unhappy! So now we do things the modern and much simpler way: the callback when data comes in just puts it on a bufchain, and the top-level ssh_scp_recv repeatedly waits until data arrives in the bufchain and then copies it to the output buffer.
-
- Nov 04, 2018
-
-
Pavel I. Kryukov authored
Configuration pointer is globally visible from winstuff.h, so it cannot be 'static' any longer.
-