Move most of ssh.c out into separate source files.
I've tried to separate out as many individually coherent changes from
this work as I could into their own commits, but here's where I run
out and have to commit the rest of this major refactoring as a
big-bang change.
Most of ssh.c is now no longer in ssh.c: all five of the main
coroutines that handle layers of the SSH-1 and SSH-2 protocols now
each have their own source file to live in, and a lot of the
supporting functions have moved into the appropriate one of those too.
The new abstraction is a vtable called 'PacketProtocolLayer', which
has an input and output packet queue. Each layer's main coroutine is
invoked from the method ssh_ppl_process_queue(), which is usually
(though not exclusively) triggered automatically when things are
pushed on the input queue. In SSH-2, the base layer is the transport
protocol, and it contains a pair of subsidiary queues by which it
passes some of its packets to the higher SSH-2 layers - first userauth
and then connection, which are peers at the same level, with the
former abdicating in favour of the latter at the appropriate moment.
SSH-1 is simpler: the whole login phase of the protocol (crypto setup
and authentication) is all in one module, and since SSH-1 has no
repeat key exchange, that setup layer abdicates in favour of the
connection phase when it's done.
ssh.c itself is now about a tenth of its old size (which all by itself
is cause for celebration!). Its main job is to set up all the layers,
hook them up to each other and to the BPP, and to funnel data back and
forth between that collection of modules and external things such as
the network and the terminal. Once it's set up a collection of packet
protocol layers, it communicates with them partly by calling methods
of the base layer (and if that's ssh2transport then it will delegate
some functionality to the corresponding methods of its higher layer),
and partly by talking directly to the connection layer no matter where
it is in the stack by means of the separate ConnectionLayer vtable
which I introduced in commit 8001dd4cb, and to which I've now added
quite a few extra methods replacing services that used to be internal
function calls within ssh.c.
(One effect of this is that the SSH-1 and SSH-2 channel storage is now
no longer shared - there are distinct struct types ssh1_channel and
ssh2_channel. That means a bit more code duplication, but on the plus
side, a lot fewer confusing conditionals in the middle of half-shared
functions, and less risk of a piece of SSH-1 escaping into SSH-2 or
vice versa, which I remember has happened at least once in the past.)
The bulk of this commit introduces the five new source files, their
common header sshppl.h and some shared supporting routines in
sshcommon.c, and rewrites nearly all of ssh.c itself. But it also
includes a couple of other changes that I couldn't separate easily
enough:
Firstly, there's a new handling for socket EOF, in which ssh.c sets an
'input_eof' flag in the BPP, and that responds by checking a flag that
tells it whether to report the EOF as an error or not. (This is the
main reason for those new BPP_READ / BPP_WAITFOR macros - they can
check the EOF flag every time the coroutine is resumed.)
Secondly, the error reporting itself is changed around again. I'd
expected to put some data fields in the public PacketProtocolLayer
structure that it could set to report errors in the same way as the
BPPs have been doing, but in the end, I decided propagating all those
data fields around was a pain and that even the BPPs shouldn't have
been doing it that way. So I've reverted to a system where everything
calls back to functions in ssh.c itself to report any connection-
ending condition. But there's a new family of those functions,
categorising the possible such conditions by semantics, and each one
has a different set of detailed effects (e.g. how rudely to close the
network connection, what exit status should be passed back to the
whole application, whether to send a disconnect message and/or display
a GUI error box).
I don't expect this to be immediately perfect: of course, the code has
been through a big upheaval, new bugs are expected, and I haven't been
able to do a full job of testing (e.g. I haven't tested every auth or
kex method). But I've checked that it _basically_ works - both SSH
protocols, all the different kinds of forwarding channel, more than
one auth method, Windows and Linux, connection sharing - and I think
it's now at the point where the easiest way to find further bugs is to
let it out into the wild and see what users can spot.
2018-09-24 17:28:16 +00:00
|
|
|
/*
|
|
|
|
* Packet protocol layer for the SSH-2 userauth protocol (RFC 4252).
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <assert.h>
|
|
|
|
|
|
|
|
#include "putty.h"
|
|
|
|
#include "ssh.h"
|
|
|
|
#include "sshbpp.h"
|
|
|
|
#include "sshppl.h"
|
|
|
|
#include "sshcr.h"
|
|
|
|
|
|
|
|
#ifndef NO_GSSAPI
|
|
|
|
#include "sshgssc.h"
|
|
|
|
#include "sshgss.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#define BANNER_LIMIT 131072
|
|
|
|
|
|
|
|
struct ssh2_userauth_state {
|
|
|
|
int crState;
|
|
|
|
|
|
|
|
PacketProtocolLayer *transport_layer, *successor_layer;
|
|
|
|
Filename *keyfile;
|
|
|
|
int tryagent, change_username;
|
|
|
|
char *hostname, *fullhostname;
|
|
|
|
char *default_username;
|
|
|
|
int try_ki_auth, try_gssapi_auth, try_gssapi_kex_auth, gssapi_fwd;
|
|
|
|
|
|
|
|
ptrlen session_id;
|
|
|
|
enum {
|
|
|
|
AUTH_TYPE_NONE,
|
|
|
|
AUTH_TYPE_PUBLICKEY,
|
|
|
|
AUTH_TYPE_PUBLICKEY_OFFER_LOUD,
|
|
|
|
AUTH_TYPE_PUBLICKEY_OFFER_QUIET,
|
|
|
|
AUTH_TYPE_PASSWORD,
|
|
|
|
AUTH_TYPE_GSSAPI, /* always QUIET */
|
|
|
|
AUTH_TYPE_KEYBOARD_INTERACTIVE,
|
|
|
|
AUTH_TYPE_KEYBOARD_INTERACTIVE_QUIET
|
|
|
|
} type;
|
|
|
|
int need_pw, can_pubkey, can_passwd, can_keyb_inter;
|
|
|
|
int userpass_ret;
|
|
|
|
int tried_pubkey_config, done_agent;
|
|
|
|
struct ssh_connection_shared_gss_state *shgss;
|
|
|
|
#ifndef NO_GSSAPI
|
|
|
|
int can_gssapi;
|
|
|
|
int can_gssapi_keyex_auth;
|
|
|
|
int tried_gssapi;
|
|
|
|
int tried_gssapi_keyex_auth;
|
|
|
|
time_t gss_cred_expiry;
|
|
|
|
Ssh_gss_buf gss_buf;
|
|
|
|
Ssh_gss_buf gss_rcvtok, gss_sndtok;
|
|
|
|
Ssh_gss_stat gss_stat;
|
|
|
|
#endif
|
|
|
|
int kbd_inter_refused;
|
|
|
|
prompts_t *cur_prompt;
|
|
|
|
int num_prompts;
|
|
|
|
char *username;
|
|
|
|
char *password;
|
|
|
|
int got_username;
|
|
|
|
strbuf *publickey_blob;
|
|
|
|
int privatekey_available, privatekey_encrypted;
|
|
|
|
char *publickey_algorithm;
|
|
|
|
char *publickey_comment;
|
|
|
|
void *agent_response_to_free;
|
|
|
|
ptrlen agent_response;
|
|
|
|
BinarySource asrc[1]; /* for reading SSH agent response */
|
|
|
|
size_t pkblob_pos_in_agent;
|
|
|
|
int keyi, nkeys;
|
|
|
|
ptrlen pk, alg, comment;
|
|
|
|
int len;
|
|
|
|
PktOut *pktout;
|
|
|
|
int want_user_input;
|
|
|
|
|
|
|
|
agent_pending_query *auth_agent_query;
|
|
|
|
bufchain banner;
|
|
|
|
|
|
|
|
PacketProtocolLayer ppl;
|
|
|
|
};
|
|
|
|
|
|
|
|
static void ssh2_userauth_free(PacketProtocolLayer *);
|
|
|
|
static void ssh2_userauth_process_queue(PacketProtocolLayer *);
|
|
|
|
static int ssh2_userauth_get_specials(
|
|
|
|
PacketProtocolLayer *ppl, add_special_fn_t add_special, void *ctx);
|
|
|
|
static void ssh2_userauth_special_cmd(PacketProtocolLayer *ppl,
|
|
|
|
SessionSpecialCode code, int arg);
|
|
|
|
static int ssh2_userauth_want_user_input(PacketProtocolLayer *ppl);
|
|
|
|
static void ssh2_userauth_got_user_input(PacketProtocolLayer *ppl);
|
|
|
|
static void ssh2_userauth_reconfigure(PacketProtocolLayer *ppl, Conf *conf);
|
|
|
|
|
|
|
|
static void ssh2_userauth_agent_query(struct ssh2_userauth_state *, strbuf *);
|
|
|
|
static void ssh2_userauth_agent_callback(void *, void *, int);
|
|
|
|
static void ssh2_userauth_add_sigblob(
|
|
|
|
struct ssh2_userauth_state *s, PktOut *pkt, ptrlen pkblob, ptrlen sigblob);
|
|
|
|
static void ssh2_userauth_add_session_id(
|
|
|
|
struct ssh2_userauth_state *s, strbuf *sigdata);
|
|
|
|
#ifndef NO_GSSAPI
|
|
|
|
static PktOut *ssh2_userauth_gss_packet(
|
|
|
|
struct ssh2_userauth_state *s, const char *authtype);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static const struct PacketProtocolLayerVtable ssh2_userauth_vtable = {
|
|
|
|
ssh2_userauth_free,
|
|
|
|
ssh2_userauth_process_queue,
|
|
|
|
ssh2_userauth_get_specials,
|
|
|
|
ssh2_userauth_special_cmd,
|
|
|
|
ssh2_userauth_want_user_input,
|
|
|
|
ssh2_userauth_got_user_input,
|
|
|
|
ssh2_userauth_reconfigure,
|
|
|
|
"ssh-userauth",
|
|
|
|
};
|
|
|
|
|
|
|
|
PacketProtocolLayer *ssh2_userauth_new(
|
|
|
|
PacketProtocolLayer *successor_layer,
|
|
|
|
const char *hostname, const char *fullhostname,
|
|
|
|
Filename *keyfile, int tryagent,
|
|
|
|
const char *default_username, int change_username,
|
|
|
|
int try_ki_auth,
|
|
|
|
int try_gssapi_auth, int try_gssapi_kex_auth,
|
|
|
|
int gssapi_fwd, struct ssh_connection_shared_gss_state *shgss)
|
|
|
|
{
|
|
|
|
struct ssh2_userauth_state *s = snew(struct ssh2_userauth_state);
|
|
|
|
memset(s, 0, sizeof(*s));
|
|
|
|
s->ppl.vt = &ssh2_userauth_vtable;
|
|
|
|
|
|
|
|
s->successor_layer = successor_layer;
|
|
|
|
s->hostname = dupstr(hostname);
|
|
|
|
s->fullhostname = dupstr(fullhostname);
|
|
|
|
s->keyfile = filename_copy(keyfile);
|
|
|
|
s->tryagent = tryagent;
|
|
|
|
s->default_username = dupstr(default_username);
|
|
|
|
s->change_username = change_username;
|
|
|
|
s->try_ki_auth = try_ki_auth;
|
|
|
|
s->try_gssapi_auth = try_gssapi_auth;
|
|
|
|
s->try_gssapi_kex_auth = try_gssapi_kex_auth;
|
|
|
|
s->gssapi_fwd = gssapi_fwd;
|
|
|
|
s->shgss = shgss;
|
|
|
|
bufchain_init(&s->banner);
|
|
|
|
|
|
|
|
return &s->ppl;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ssh2_userauth_set_transport_layer(PacketProtocolLayer *userauth,
|
|
|
|
PacketProtocolLayer *transport)
|
|
|
|
{
|
|
|
|
struct ssh2_userauth_state *s =
|
2018-10-05 22:49:08 +00:00
|
|
|
container_of(userauth, struct ssh2_userauth_state, ppl);
|
Move most of ssh.c out into separate source files.
I've tried to separate out as many individually coherent changes from
this work as I could into their own commits, but here's where I run
out and have to commit the rest of this major refactoring as a
big-bang change.
Most of ssh.c is now no longer in ssh.c: all five of the main
coroutines that handle layers of the SSH-1 and SSH-2 protocols now
each have their own source file to live in, and a lot of the
supporting functions have moved into the appropriate one of those too.
The new abstraction is a vtable called 'PacketProtocolLayer', which
has an input and output packet queue. Each layer's main coroutine is
invoked from the method ssh_ppl_process_queue(), which is usually
(though not exclusively) triggered automatically when things are
pushed on the input queue. In SSH-2, the base layer is the transport
protocol, and it contains a pair of subsidiary queues by which it
passes some of its packets to the higher SSH-2 layers - first userauth
and then connection, which are peers at the same level, with the
former abdicating in favour of the latter at the appropriate moment.
SSH-1 is simpler: the whole login phase of the protocol (crypto setup
and authentication) is all in one module, and since SSH-1 has no
repeat key exchange, that setup layer abdicates in favour of the
connection phase when it's done.
ssh.c itself is now about a tenth of its old size (which all by itself
is cause for celebration!). Its main job is to set up all the layers,
hook them up to each other and to the BPP, and to funnel data back and
forth between that collection of modules and external things such as
the network and the terminal. Once it's set up a collection of packet
protocol layers, it communicates with them partly by calling methods
of the base layer (and if that's ssh2transport then it will delegate
some functionality to the corresponding methods of its higher layer),
and partly by talking directly to the connection layer no matter where
it is in the stack by means of the separate ConnectionLayer vtable
which I introduced in commit 8001dd4cb, and to which I've now added
quite a few extra methods replacing services that used to be internal
function calls within ssh.c.
(One effect of this is that the SSH-1 and SSH-2 channel storage is now
no longer shared - there are distinct struct types ssh1_channel and
ssh2_channel. That means a bit more code duplication, but on the plus
side, a lot fewer confusing conditionals in the middle of half-shared
functions, and less risk of a piece of SSH-1 escaping into SSH-2 or
vice versa, which I remember has happened at least once in the past.)
The bulk of this commit introduces the five new source files, their
common header sshppl.h and some shared supporting routines in
sshcommon.c, and rewrites nearly all of ssh.c itself. But it also
includes a couple of other changes that I couldn't separate easily
enough:
Firstly, there's a new handling for socket EOF, in which ssh.c sets an
'input_eof' flag in the BPP, and that responds by checking a flag that
tells it whether to report the EOF as an error or not. (This is the
main reason for those new BPP_READ / BPP_WAITFOR macros - they can
check the EOF flag every time the coroutine is resumed.)
Secondly, the error reporting itself is changed around again. I'd
expected to put some data fields in the public PacketProtocolLayer
structure that it could set to report errors in the same way as the
BPPs have been doing, but in the end, I decided propagating all those
data fields around was a pain and that even the BPPs shouldn't have
been doing it that way. So I've reverted to a system where everything
calls back to functions in ssh.c itself to report any connection-
ending condition. But there's a new family of those functions,
categorising the possible such conditions by semantics, and each one
has a different set of detailed effects (e.g. how rudely to close the
network connection, what exit status should be passed back to the
whole application, whether to send a disconnect message and/or display
a GUI error box).
I don't expect this to be immediately perfect: of course, the code has
been through a big upheaval, new bugs are expected, and I haven't been
able to do a full job of testing (e.g. I haven't tested every auth or
kex method). But I've checked that it _basically_ works - both SSH
protocols, all the different kinds of forwarding channel, more than
one auth method, Windows and Linux, connection sharing - and I think
it's now at the point where the easiest way to find further bugs is to
let it out into the wild and see what users can spot.
2018-09-24 17:28:16 +00:00
|
|
|
s->transport_layer = transport;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void ssh2_userauth_free(PacketProtocolLayer *ppl)
|
|
|
|
{
|
|
|
|
struct ssh2_userauth_state *s =
|
2018-10-05 22:49:08 +00:00
|
|
|
container_of(ppl, struct ssh2_userauth_state, ppl);
|
Move most of ssh.c out into separate source files.
I've tried to separate out as many individually coherent changes from
this work as I could into their own commits, but here's where I run
out and have to commit the rest of this major refactoring as a
big-bang change.
Most of ssh.c is now no longer in ssh.c: all five of the main
coroutines that handle layers of the SSH-1 and SSH-2 protocols now
each have their own source file to live in, and a lot of the
supporting functions have moved into the appropriate one of those too.
The new abstraction is a vtable called 'PacketProtocolLayer', which
has an input and output packet queue. Each layer's main coroutine is
invoked from the method ssh_ppl_process_queue(), which is usually
(though not exclusively) triggered automatically when things are
pushed on the input queue. In SSH-2, the base layer is the transport
protocol, and it contains a pair of subsidiary queues by which it
passes some of its packets to the higher SSH-2 layers - first userauth
and then connection, which are peers at the same level, with the
former abdicating in favour of the latter at the appropriate moment.
SSH-1 is simpler: the whole login phase of the protocol (crypto setup
and authentication) is all in one module, and since SSH-1 has no
repeat key exchange, that setup layer abdicates in favour of the
connection phase when it's done.
ssh.c itself is now about a tenth of its old size (which all by itself
is cause for celebration!). Its main job is to set up all the layers,
hook them up to each other and to the BPP, and to funnel data back and
forth between that collection of modules and external things such as
the network and the terminal. Once it's set up a collection of packet
protocol layers, it communicates with them partly by calling methods
of the base layer (and if that's ssh2transport then it will delegate
some functionality to the corresponding methods of its higher layer),
and partly by talking directly to the connection layer no matter where
it is in the stack by means of the separate ConnectionLayer vtable
which I introduced in commit 8001dd4cb, and to which I've now added
quite a few extra methods replacing services that used to be internal
function calls within ssh.c.
(One effect of this is that the SSH-1 and SSH-2 channel storage is now
no longer shared - there are distinct struct types ssh1_channel and
ssh2_channel. That means a bit more code duplication, but on the plus
side, a lot fewer confusing conditionals in the middle of half-shared
functions, and less risk of a piece of SSH-1 escaping into SSH-2 or
vice versa, which I remember has happened at least once in the past.)
The bulk of this commit introduces the five new source files, their
common header sshppl.h and some shared supporting routines in
sshcommon.c, and rewrites nearly all of ssh.c itself. But it also
includes a couple of other changes that I couldn't separate easily
enough:
Firstly, there's a new handling for socket EOF, in which ssh.c sets an
'input_eof' flag in the BPP, and that responds by checking a flag that
tells it whether to report the EOF as an error or not. (This is the
main reason for those new BPP_READ / BPP_WAITFOR macros - they can
check the EOF flag every time the coroutine is resumed.)
Secondly, the error reporting itself is changed around again. I'd
expected to put some data fields in the public PacketProtocolLayer
structure that it could set to report errors in the same way as the
BPPs have been doing, but in the end, I decided propagating all those
data fields around was a pain and that even the BPPs shouldn't have
been doing it that way. So I've reverted to a system where everything
calls back to functions in ssh.c itself to report any connection-
ending condition. But there's a new family of those functions,
categorising the possible such conditions by semantics, and each one
has a different set of detailed effects (e.g. how rudely to close the
network connection, what exit status should be passed back to the
whole application, whether to send a disconnect message and/or display
a GUI error box).
I don't expect this to be immediately perfect: of course, the code has
been through a big upheaval, new bugs are expected, and I haven't been
able to do a full job of testing (e.g. I haven't tested every auth or
kex method). But I've checked that it _basically_ works - both SSH
protocols, all the different kinds of forwarding channel, more than
one auth method, Windows and Linux, connection sharing - and I think
it's now at the point where the easiest way to find further bugs is to
let it out into the wild and see what users can spot.
2018-09-24 17:28:16 +00:00
|
|
|
bufchain_clear(&s->banner);
|
|
|
|
|
|
|
|
if (s->successor_layer)
|
|
|
|
ssh_ppl_free(s->successor_layer);
|
|
|
|
|
|
|
|
sfree(s->agent_response_to_free);
|
|
|
|
if (s->auth_agent_query)
|
|
|
|
agent_cancel_query(s->auth_agent_query);
|
|
|
|
filename_free(s->keyfile);
|
|
|
|
sfree(s->default_username);
|
|
|
|
sfree(s->hostname);
|
|
|
|
sfree(s->fullhostname);
|
|
|
|
sfree(s);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void ssh2_userauth_filter_queue(struct ssh2_userauth_state *s)
|
|
|
|
{
|
|
|
|
PktIn *pktin;
|
|
|
|
ptrlen string;
|
|
|
|
|
|
|
|
while ((pktin = pq_peek(s->ppl.in_pq)) != NULL) {
|
|
|
|
switch (pktin->type) {
|
|
|
|
case SSH2_MSG_USERAUTH_BANNER:
|
|
|
|
string = get_string(pktin);
|
|
|
|
if (string.len > BANNER_LIMIT - bufchain_size(&s->banner))
|
|
|
|
string.len = BANNER_LIMIT - bufchain_size(&s->banner);
|
|
|
|
sanitise_term_data(&s->banner, string.ptr, string.len);
|
|
|
|
pq_pop(s->ppl.in_pq);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static PktIn *ssh2_userauth_pop(struct ssh2_userauth_state *s)
|
|
|
|
{
|
|
|
|
ssh2_userauth_filter_queue(s);
|
|
|
|
return pq_pop(s->ppl.in_pq);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl)
|
|
|
|
{
|
|
|
|
struct ssh2_userauth_state *s =
|
2018-10-05 22:49:08 +00:00
|
|
|
container_of(ppl, struct ssh2_userauth_state, ppl);
|
Move most of ssh.c out into separate source files.
I've tried to separate out as many individually coherent changes from
this work as I could into their own commits, but here's where I run
out and have to commit the rest of this major refactoring as a
big-bang change.
Most of ssh.c is now no longer in ssh.c: all five of the main
coroutines that handle layers of the SSH-1 and SSH-2 protocols now
each have their own source file to live in, and a lot of the
supporting functions have moved into the appropriate one of those too.
The new abstraction is a vtable called 'PacketProtocolLayer', which
has an input and output packet queue. Each layer's main coroutine is
invoked from the method ssh_ppl_process_queue(), which is usually
(though not exclusively) triggered automatically when things are
pushed on the input queue. In SSH-2, the base layer is the transport
protocol, and it contains a pair of subsidiary queues by which it
passes some of its packets to the higher SSH-2 layers - first userauth
and then connection, which are peers at the same level, with the
former abdicating in favour of the latter at the appropriate moment.
SSH-1 is simpler: the whole login phase of the protocol (crypto setup
and authentication) is all in one module, and since SSH-1 has no
repeat key exchange, that setup layer abdicates in favour of the
connection phase when it's done.
ssh.c itself is now about a tenth of its old size (which all by itself
is cause for celebration!). Its main job is to set up all the layers,
hook them up to each other and to the BPP, and to funnel data back and
forth between that collection of modules and external things such as
the network and the terminal. Once it's set up a collection of packet
protocol layers, it communicates with them partly by calling methods
of the base layer (and if that's ssh2transport then it will delegate
some functionality to the corresponding methods of its higher layer),
and partly by talking directly to the connection layer no matter where
it is in the stack by means of the separate ConnectionLayer vtable
which I introduced in commit 8001dd4cb, and to which I've now added
quite a few extra methods replacing services that used to be internal
function calls within ssh.c.
(One effect of this is that the SSH-1 and SSH-2 channel storage is now
no longer shared - there are distinct struct types ssh1_channel and
ssh2_channel. That means a bit more code duplication, but on the plus
side, a lot fewer confusing conditionals in the middle of half-shared
functions, and less risk of a piece of SSH-1 escaping into SSH-2 or
vice versa, which I remember has happened at least once in the past.)
The bulk of this commit introduces the five new source files, their
common header sshppl.h and some shared supporting routines in
sshcommon.c, and rewrites nearly all of ssh.c itself. But it also
includes a couple of other changes that I couldn't separate easily
enough:
Firstly, there's a new handling for socket EOF, in which ssh.c sets an
'input_eof' flag in the BPP, and that responds by checking a flag that
tells it whether to report the EOF as an error or not. (This is the
main reason for those new BPP_READ / BPP_WAITFOR macros - they can
check the EOF flag every time the coroutine is resumed.)
Secondly, the error reporting itself is changed around again. I'd
expected to put some data fields in the public PacketProtocolLayer
structure that it could set to report errors in the same way as the
BPPs have been doing, but in the end, I decided propagating all those
data fields around was a pain and that even the BPPs shouldn't have
been doing it that way. So I've reverted to a system where everything
calls back to functions in ssh.c itself to report any connection-
ending condition. But there's a new family of those functions,
categorising the possible such conditions by semantics, and each one
has a different set of detailed effects (e.g. how rudely to close the
network connection, what exit status should be passed back to the
whole application, whether to send a disconnect message and/or display
a GUI error box).
I don't expect this to be immediately perfect: of course, the code has
been through a big upheaval, new bugs are expected, and I haven't been
able to do a full job of testing (e.g. I haven't tested every auth or
kex method). But I've checked that it _basically_ works - both SSH
protocols, all the different kinds of forwarding channel, more than
one auth method, Windows and Linux, connection sharing - and I think
it's now at the point where the easiest way to find further bugs is to
let it out into the wild and see what users can spot.
2018-09-24 17:28:16 +00:00
|
|
|
PktIn *pktin;
|
|
|
|
|
|
|
|
ssh2_userauth_filter_queue(s); /* no matter why we were called */
|
|
|
|
|
|
|
|
crBegin(s->crState);
|
|
|
|
|
|
|
|
#ifndef NO_GSSAPI
|
|
|
|
s->tried_gssapi = FALSE;
|
|
|
|
s->tried_gssapi_keyex_auth = FALSE;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Misc one-time setup for authentication.
|
|
|
|
*/
|
|
|
|
s->publickey_blob = NULL;
|
|
|
|
s->session_id = ssh2_transport_get_session_id(s->transport_layer);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Load the public half of any configured public key file for
|
|
|
|
* later use.
|
|
|
|
*/
|
|
|
|
if (!filename_is_null(s->keyfile)) {
|
|
|
|
int keytype;
|
|
|
|
ppl_logevent(("Reading key file \"%.150s\"",
|
|
|
|
filename_to_str(s->keyfile)));
|
|
|
|
keytype = key_type(s->keyfile);
|
|
|
|
if (keytype == SSH_KEYTYPE_SSH2 ||
|
|
|
|
keytype == SSH_KEYTYPE_SSH2_PUBLIC_RFC4716 ||
|
|
|
|
keytype == SSH_KEYTYPE_SSH2_PUBLIC_OPENSSH) {
|
|
|
|
const char *error;
|
|
|
|
s->publickey_blob = strbuf_new();
|
|
|
|
if (ssh2_userkey_loadpub(s->keyfile,
|
|
|
|
&s->publickey_algorithm,
|
|
|
|
BinarySink_UPCAST(s->publickey_blob),
|
|
|
|
&s->publickey_comment, &error)) {
|
|
|
|
s->privatekey_available = (keytype == SSH_KEYTYPE_SSH2);
|
|
|
|
if (!s->privatekey_available)
|
|
|
|
ppl_logevent(("Key file contains public key only"));
|
|
|
|
s->privatekey_encrypted =
|
|
|
|
ssh2_userkey_encrypted(s->keyfile, NULL);
|
|
|
|
} else {
|
|
|
|
ppl_logevent(("Unable to load key (%s)", error));
|
|
|
|
ppl_printf(("Unable to load key file \"%s\" (%s)\r\n",
|
|
|
|
filename_to_str(s->keyfile), error));
|
|
|
|
strbuf_free(s->publickey_blob);
|
|
|
|
s->publickey_blob = NULL;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
ppl_logevent(("Unable to use this key file (%s)",
|
|
|
|
key_type_to_str(keytype)));
|
|
|
|
ppl_printf(("Unable to use key file \"%s\" (%s)\r\n",
|
|
|
|
filename_to_str(s->keyfile),
|
|
|
|
key_type_to_str(keytype)));
|
|
|
|
s->publickey_blob = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Find out about any keys Pageant has (but if there's a public
|
|
|
|
* key configured, filter out all others).
|
|
|
|
*/
|
|
|
|
s->nkeys = 0;
|
|
|
|
s->pkblob_pos_in_agent = 0;
|
|
|
|
if (s->tryagent && agent_exists()) {
|
|
|
|
ppl_logevent(("Pageant is running. Requesting keys."));
|
|
|
|
|
|
|
|
/* Request the keys held by the agent. */
|
|
|
|
{
|
|
|
|
strbuf *request = strbuf_new_for_agent_query();
|
|
|
|
put_byte(request, SSH2_AGENTC_REQUEST_IDENTITIES);
|
|
|
|
ssh2_userauth_agent_query(s, request);
|
|
|
|
strbuf_free(request);
|
|
|
|
crWaitUntilV(!s->auth_agent_query);
|
|
|
|
}
|
|
|
|
BinarySource_BARE_INIT(
|
|
|
|
s->asrc, s->agent_response.ptr, s->agent_response.len);
|
|
|
|
|
|
|
|
get_uint32(s->asrc); /* skip length field */
|
|
|
|
if (get_byte(s->asrc) == SSH2_AGENT_IDENTITIES_ANSWER) {
|
|
|
|
int keyi;
|
|
|
|
|
|
|
|
s->nkeys = toint(get_uint32(s->asrc));
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Vet the Pageant response to ensure that the key count
|
|
|
|
* and blob lengths make sense.
|
|
|
|
*/
|
|
|
|
if (s->nkeys < 0) {
|
|
|
|
ppl_logevent(("Pageant response contained a negative"
|
|
|
|
" key count %d", s->nkeys));
|
|
|
|
s->nkeys = 0;
|
|
|
|
goto done_agent_query;
|
|
|
|
} else {
|
|
|
|
ppl_logevent(("Pageant has %d SSH-2 keys", s->nkeys));
|
|
|
|
|
|
|
|
/* See if configured key is in agent. */
|
|
|
|
for (keyi = 0; keyi < s->nkeys; keyi++) {
|
|
|
|
size_t pos = s->asrc->pos;
|
|
|
|
ptrlen blob = get_string(s->asrc);
|
|
|
|
get_string(s->asrc); /* skip comment */
|
|
|
|
if (get_err(s->asrc)) {
|
|
|
|
ppl_logevent(("Pageant response was truncated"));
|
|
|
|
s->nkeys = 0;
|
|
|
|
goto done_agent_query;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (s->publickey_blob &&
|
|
|
|
blob.len == s->publickey_blob->len &&
|
|
|
|
!memcmp(blob.ptr, s->publickey_blob->s,
|
|
|
|
s->publickey_blob->len)) {
|
|
|
|
ppl_logevent(("Pageant key #%d matches "
|
|
|
|
"configured key file", keyi));
|
|
|
|
s->keyi = keyi;
|
|
|
|
s->pkblob_pos_in_agent = pos;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (s->publickey_blob && !s->pkblob_pos_in_agent) {
|
|
|
|
ppl_logevent(("Configured key file not in Pageant"));
|
|
|
|
s->nkeys = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
ppl_logevent(("Failed to get reply from Pageant"));
|
|
|
|
}
|
|
|
|
done_agent_query:;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We repeat this whole loop, including the username prompt,
|
|
|
|
* until we manage a successful authentication. If the user
|
|
|
|
* types the wrong _password_, they can be sent back to the
|
|
|
|
* beginning to try another username, if this is configured on.
|
|
|
|
* (If they specify a username in the config, they are never
|
|
|
|
* asked, even if they do give a wrong password.)
|
|
|
|
*
|
|
|
|
* I think this best serves the needs of
|
|
|
|
*
|
|
|
|
* - the people who have no configuration, no keys, and just
|
|
|
|
* want to try repeated (username,password) pairs until they
|
|
|
|
* type both correctly
|
|
|
|
*
|
|
|
|
* - people who have keys and configuration but occasionally
|
|
|
|
* need to fall back to passwords
|
|
|
|
*
|
|
|
|
* - people with a key held in Pageant, who might not have
|
|
|
|
* logged in to a particular machine before; so they want to
|
|
|
|
* type a username, and then _either_ their key will be
|
|
|
|
* accepted, _or_ they will type a password. If they mistype
|
|
|
|
* the username they will want to be able to get back and
|
|
|
|
* retype it!
|
|
|
|
*/
|
|
|
|
s->got_username = FALSE;
|
|
|
|
while (1) {
|
|
|
|
/*
|
|
|
|
* Get a username.
|
|
|
|
*/
|
|
|
|
if (s->got_username && s->change_username) {
|
|
|
|
/*
|
|
|
|
* We got a username last time round this loop, and
|
|
|
|
* with change_username turned off we don't try to get
|
|
|
|
* it again.
|
|
|
|
*/
|
|
|
|
} else if ((s->username = s->default_username) == NULL) {
|
New abstraction 'Seat', to pass to backends.
This is a new vtable-based abstraction which is passed to a backend in
place of Frontend, and it implements only the subset of the Frontend
functions needed by a backend. (Many other Frontend functions still
exist, notably the wide range of things called by terminal.c providing
platform-independent operations on the GUI terminal window.)
The purpose of making it a vtable is that this opens up the
possibility of creating a backend as an internal implementation detail
of some other activity, by providing just that one backend with a
custom Seat that implements the methods differently.
For example, this refactoring should make it feasible to directly
implement an SSH proxy type, aka the 'jump host' feature supported by
OpenSSH, aka 'open a secondary SSH session in MAINCHAN_DIRECT_TCP
mode, and then expose the main channel of that as the Socket for the
primary connection'. (Which of course you can already do by spawning
'plink -nc' as a separate proxy process, but this would permit it in
the _same_ process without anything getting confused.)
I've centralised a full set of stub methods in misc.c for the new
abstraction, which allows me to get rid of several annoying stubs in
the previous code. Also, while I'm here, I've moved a lot of
duplicated modalfatalbox() type functions from application main
program files into wincons.c / uxcons.c, which I think saves
duplication overall. (A minor visible effect is that the prefixes on
those console-based fatal error messages will now be more consistent
between applications.)
2018-10-11 18:58:42 +00:00
|
|
|
s->cur_prompt = new_prompts();
|
Move most of ssh.c out into separate source files.
I've tried to separate out as many individually coherent changes from
this work as I could into their own commits, but here's where I run
out and have to commit the rest of this major refactoring as a
big-bang change.
Most of ssh.c is now no longer in ssh.c: all five of the main
coroutines that handle layers of the SSH-1 and SSH-2 protocols now
each have their own source file to live in, and a lot of the
supporting functions have moved into the appropriate one of those too.
The new abstraction is a vtable called 'PacketProtocolLayer', which
has an input and output packet queue. Each layer's main coroutine is
invoked from the method ssh_ppl_process_queue(), which is usually
(though not exclusively) triggered automatically when things are
pushed on the input queue. In SSH-2, the base layer is the transport
protocol, and it contains a pair of subsidiary queues by which it
passes some of its packets to the higher SSH-2 layers - first userauth
and then connection, which are peers at the same level, with the
former abdicating in favour of the latter at the appropriate moment.
SSH-1 is simpler: the whole login phase of the protocol (crypto setup
and authentication) is all in one module, and since SSH-1 has no
repeat key exchange, that setup layer abdicates in favour of the
connection phase when it's done.
ssh.c itself is now about a tenth of its old size (which all by itself
is cause for celebration!). Its main job is to set up all the layers,
hook them up to each other and to the BPP, and to funnel data back and
forth between that collection of modules and external things such as
the network and the terminal. Once it's set up a collection of packet
protocol layers, it communicates with them partly by calling methods
of the base layer (and if that's ssh2transport then it will delegate
some functionality to the corresponding methods of its higher layer),
and partly by talking directly to the connection layer no matter where
it is in the stack by means of the separate ConnectionLayer vtable
which I introduced in commit 8001dd4cb, and to which I've now added
quite a few extra methods replacing services that used to be internal
function calls within ssh.c.
(One effect of this is that the SSH-1 and SSH-2 channel storage is now
no longer shared - there are distinct struct types ssh1_channel and
ssh2_channel. That means a bit more code duplication, but on the plus
side, a lot fewer confusing conditionals in the middle of half-shared
functions, and less risk of a piece of SSH-1 escaping into SSH-2 or
vice versa, which I remember has happened at least once in the past.)
The bulk of this commit introduces the five new source files, their
common header sshppl.h and some shared supporting routines in
sshcommon.c, and rewrites nearly all of ssh.c itself. But it also
includes a couple of other changes that I couldn't separate easily
enough:
Firstly, there's a new handling for socket EOF, in which ssh.c sets an
'input_eof' flag in the BPP, and that responds by checking a flag that
tells it whether to report the EOF as an error or not. (This is the
main reason for those new BPP_READ / BPP_WAITFOR macros - they can
check the EOF flag every time the coroutine is resumed.)
Secondly, the error reporting itself is changed around again. I'd
expected to put some data fields in the public PacketProtocolLayer
structure that it could set to report errors in the same way as the
BPPs have been doing, but in the end, I decided propagating all those
data fields around was a pain and that even the BPPs shouldn't have
been doing it that way. So I've reverted to a system where everything
calls back to functions in ssh.c itself to report any connection-
ending condition. But there's a new family of those functions,
categorising the possible such conditions by semantics, and each one
has a different set of detailed effects (e.g. how rudely to close the
network connection, what exit status should be passed back to the
whole application, whether to send a disconnect message and/or display
a GUI error box).
I don't expect this to be immediately perfect: of course, the code has
been through a big upheaval, new bugs are expected, and I haven't been
able to do a full job of testing (e.g. I haven't tested every auth or
kex method). But I've checked that it _basically_ works - both SSH
protocols, all the different kinds of forwarding channel, more than
one auth method, Windows and Linux, connection sharing - and I think
it's now at the point where the easiest way to find further bugs is to
let it out into the wild and see what users can spot.
2018-09-24 17:28:16 +00:00
|
|
|
s->cur_prompt->to_server = TRUE;
|
|
|
|
s->cur_prompt->name = dupstr("SSH login name");
|
|
|
|
add_prompt(s->cur_prompt, dupstr("login as: "), TRUE);
|
New abstraction 'Seat', to pass to backends.
This is a new vtable-based abstraction which is passed to a backend in
place of Frontend, and it implements only the subset of the Frontend
functions needed by a backend. (Many other Frontend functions still
exist, notably the wide range of things called by terminal.c providing
platform-independent operations on the GUI terminal window.)
The purpose of making it a vtable is that this opens up the
possibility of creating a backend as an internal implementation detail
of some other activity, by providing just that one backend with a
custom Seat that implements the methods differently.
For example, this refactoring should make it feasible to directly
implement an SSH proxy type, aka the 'jump host' feature supported by
OpenSSH, aka 'open a secondary SSH session in MAINCHAN_DIRECT_TCP
mode, and then expose the main channel of that as the Socket for the
primary connection'. (Which of course you can already do by spawning
'plink -nc' as a separate proxy process, but this would permit it in
the _same_ process without anything getting confused.)
I've centralised a full set of stub methods in misc.c for the new
abstraction, which allows me to get rid of several annoying stubs in
the previous code. Also, while I'm here, I've moved a lot of
duplicated modalfatalbox() type functions from application main
program files into wincons.c / uxcons.c, which I think saves
duplication overall. (A minor visible effect is that the prefixes on
those console-based fatal error messages will now be more consistent
between applications.)
2018-10-11 18:58:42 +00:00
|
|
|
s->userpass_ret = seat_get_userpass_input(
|
|
|
|
s->ppl.seat, s->cur_prompt, NULL);
|
Move most of ssh.c out into separate source files.
I've tried to separate out as many individually coherent changes from
this work as I could into their own commits, but here's where I run
out and have to commit the rest of this major refactoring as a
big-bang change.
Most of ssh.c is now no longer in ssh.c: all five of the main
coroutines that handle layers of the SSH-1 and SSH-2 protocols now
each have their own source file to live in, and a lot of the
supporting functions have moved into the appropriate one of those too.
The new abstraction is a vtable called 'PacketProtocolLayer', which
has an input and output packet queue. Each layer's main coroutine is
invoked from the method ssh_ppl_process_queue(), which is usually
(though not exclusively) triggered automatically when things are
pushed on the input queue. In SSH-2, the base layer is the transport
protocol, and it contains a pair of subsidiary queues by which it
passes some of its packets to the higher SSH-2 layers - first userauth
and then connection, which are peers at the same level, with the
former abdicating in favour of the latter at the appropriate moment.
SSH-1 is simpler: the whole login phase of the protocol (crypto setup
and authentication) is all in one module, and since SSH-1 has no
repeat key exchange, that setup layer abdicates in favour of the
connection phase when it's done.
ssh.c itself is now about a tenth of its old size (which all by itself
is cause for celebration!). Its main job is to set up all the layers,
hook them up to each other and to the BPP, and to funnel data back and
forth between that collection of modules and external things such as
the network and the terminal. Once it's set up a collection of packet
protocol layers, it communicates with them partly by calling methods
of the base layer (and if that's ssh2transport then it will delegate
some functionality to the corresponding methods of its higher layer),
and partly by talking directly to the connection layer no matter where
it is in the stack by means of the separate ConnectionLayer vtable
which I introduced in commit 8001dd4cb, and to which I've now added
quite a few extra methods replacing services that used to be internal
function calls within ssh.c.
(One effect of this is that the SSH-1 and SSH-2 channel storage is now
no longer shared - there are distinct struct types ssh1_channel and
ssh2_channel. That means a bit more code duplication, but on the plus
side, a lot fewer confusing conditionals in the middle of half-shared
functions, and less risk of a piece of SSH-1 escaping into SSH-2 or
vice versa, which I remember has happened at least once in the past.)
The bulk of this commit introduces the five new source files, their
common header sshppl.h and some shared supporting routines in
sshcommon.c, and rewrites nearly all of ssh.c itself. But it also
includes a couple of other changes that I couldn't separate easily
enough:
Firstly, there's a new handling for socket EOF, in which ssh.c sets an
'input_eof' flag in the BPP, and that responds by checking a flag that
tells it whether to report the EOF as an error or not. (This is the
main reason for those new BPP_READ / BPP_WAITFOR macros - they can
check the EOF flag every time the coroutine is resumed.)
Secondly, the error reporting itself is changed around again. I'd
expected to put some data fields in the public PacketProtocolLayer
structure that it could set to report errors in the same way as the
BPPs have been doing, but in the end, I decided propagating all those
data fields around was a pain and that even the BPPs shouldn't have
been doing it that way. So I've reverted to a system where everything
calls back to functions in ssh.c itself to report any connection-
ending condition. But there's a new family of those functions,
categorising the possible such conditions by semantics, and each one
has a different set of detailed effects (e.g. how rudely to close the
network connection, what exit status should be passed back to the
whole application, whether to send a disconnect message and/or display
a GUI error box).
I don't expect this to be immediately perfect: of course, the code has
been through a big upheaval, new bugs are expected, and I haven't been
able to do a full job of testing (e.g. I haven't tested every auth or
kex method). But I've checked that it _basically_ works - both SSH
protocols, all the different kinds of forwarding channel, more than
one auth method, Windows and Linux, connection sharing - and I think
it's now at the point where the easiest way to find further bugs is to
let it out into the wild and see what users can spot.
2018-09-24 17:28:16 +00:00
|
|
|
while (1) {
|
|
|
|
while (s->userpass_ret < 0 &&
|
|
|
|
bufchain_size(s->ppl.user_input) > 0)
|
New abstraction 'Seat', to pass to backends.
This is a new vtable-based abstraction which is passed to a backend in
place of Frontend, and it implements only the subset of the Frontend
functions needed by a backend. (Many other Frontend functions still
exist, notably the wide range of things called by terminal.c providing
platform-independent operations on the GUI terminal window.)
The purpose of making it a vtable is that this opens up the
possibility of creating a backend as an internal implementation detail
of some other activity, by providing just that one backend with a
custom Seat that implements the methods differently.
For example, this refactoring should make it feasible to directly
implement an SSH proxy type, aka the 'jump host' feature supported by
OpenSSH, aka 'open a secondary SSH session in MAINCHAN_DIRECT_TCP
mode, and then expose the main channel of that as the Socket for the
primary connection'. (Which of course you can already do by spawning
'plink -nc' as a separate proxy process, but this would permit it in
the _same_ process without anything getting confused.)
I've centralised a full set of stub methods in misc.c for the new
abstraction, which allows me to get rid of several annoying stubs in
the previous code. Also, while I'm here, I've moved a lot of
duplicated modalfatalbox() type functions from application main
program files into wincons.c / uxcons.c, which I think saves
duplication overall. (A minor visible effect is that the prefixes on
those console-based fatal error messages will now be more consistent
between applications.)
2018-10-11 18:58:42 +00:00
|
|
|
s->userpass_ret = seat_get_userpass_input(
|
|
|
|
s->ppl.seat, s->cur_prompt, s->ppl.user_input);
|
Move most of ssh.c out into separate source files.
I've tried to separate out as many individually coherent changes from
this work as I could into their own commits, but here's where I run
out and have to commit the rest of this major refactoring as a
big-bang change.
Most of ssh.c is now no longer in ssh.c: all five of the main
coroutines that handle layers of the SSH-1 and SSH-2 protocols now
each have their own source file to live in, and a lot of the
supporting functions have moved into the appropriate one of those too.
The new abstraction is a vtable called 'PacketProtocolLayer', which
has an input and output packet queue. Each layer's main coroutine is
invoked from the method ssh_ppl_process_queue(), which is usually
(though not exclusively) triggered automatically when things are
pushed on the input queue. In SSH-2, the base layer is the transport
protocol, and it contains a pair of subsidiary queues by which it
passes some of its packets to the higher SSH-2 layers - first userauth
and then connection, which are peers at the same level, with the
former abdicating in favour of the latter at the appropriate moment.
SSH-1 is simpler: the whole login phase of the protocol (crypto setup
and authentication) is all in one module, and since SSH-1 has no
repeat key exchange, that setup layer abdicates in favour of the
connection phase when it's done.
ssh.c itself is now about a tenth of its old size (which all by itself
is cause for celebration!). Its main job is to set up all the layers,
hook them up to each other and to the BPP, and to funnel data back and
forth between that collection of modules and external things such as
the network and the terminal. Once it's set up a collection of packet
protocol layers, it communicates with them partly by calling methods
of the base layer (and if that's ssh2transport then it will delegate
some functionality to the corresponding methods of its higher layer),
and partly by talking directly to the connection layer no matter where
it is in the stack by means of the separate ConnectionLayer vtable
which I introduced in commit 8001dd4cb, and to which I've now added
quite a few extra methods replacing services that used to be internal
function calls within ssh.c.
(One effect of this is that the SSH-1 and SSH-2 channel storage is now
no longer shared - there are distinct struct types ssh1_channel and
ssh2_channel. That means a bit more code duplication, but on the plus
side, a lot fewer confusing conditionals in the middle of half-shared
functions, and less risk of a piece of SSH-1 escaping into SSH-2 or
vice versa, which I remember has happened at least once in the past.)
The bulk of this commit introduces the five new source files, their
common header sshppl.h and some shared supporting routines in
sshcommon.c, and rewrites nearly all of ssh.c itself. But it also
includes a couple of other changes that I couldn't separate easily
enough:
Firstly, there's a new handling for socket EOF, in which ssh.c sets an
'input_eof' flag in the BPP, and that responds by checking a flag that
tells it whether to report the EOF as an error or not. (This is the
main reason for those new BPP_READ / BPP_WAITFOR macros - they can
check the EOF flag every time the coroutine is resumed.)
Secondly, the error reporting itself is changed around again. I'd
expected to put some data fields in the public PacketProtocolLayer
structure that it could set to report errors in the same way as the
BPPs have been doing, but in the end, I decided propagating all those
data fields around was a pain and that even the BPPs shouldn't have
been doing it that way. So I've reverted to a system where everything
calls back to functions in ssh.c itself to report any connection-
ending condition. But there's a new family of those functions,
categorising the possible such conditions by semantics, and each one
has a different set of detailed effects (e.g. how rudely to close the
network connection, what exit status should be passed back to the
whole application, whether to send a disconnect message and/or display
a GUI error box).
I don't expect this to be immediately perfect: of course, the code has
been through a big upheaval, new bugs are expected, and I haven't been
able to do a full job of testing (e.g. I haven't tested every auth or
kex method). But I've checked that it _basically_ works - both SSH
protocols, all the different kinds of forwarding channel, more than
one auth method, Windows and Linux, connection sharing - and I think
it's now at the point where the easiest way to find further bugs is to
let it out into the wild and see what users can spot.
2018-09-24 17:28:16 +00:00
|
|
|
|
|
|
|
if (s->userpass_ret >= 0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
s->want_user_input = TRUE;
|
|
|
|
crReturnV;
|
|
|
|
s->want_user_input = FALSE;
|
|
|
|
}
|
|
|
|
if (!s->userpass_ret) {
|
|
|
|
/*
|
New abstraction 'Seat', to pass to backends.
This is a new vtable-based abstraction which is passed to a backend in
place of Frontend, and it implements only the subset of the Frontend
functions needed by a backend. (Many other Frontend functions still
exist, notably the wide range of things called by terminal.c providing
platform-independent operations on the GUI terminal window.)
The purpose of making it a vtable is that this opens up the
possibility of creating a backend as an internal implementation detail
of some other activity, by providing just that one backend with a
custom Seat that implements the methods differently.
For example, this refactoring should make it feasible to directly
implement an SSH proxy type, aka the 'jump host' feature supported by
OpenSSH, aka 'open a secondary SSH session in MAINCHAN_DIRECT_TCP
mode, and then expose the main channel of that as the Socket for the
primary connection'. (Which of course you can already do by spawning
'plink -nc' as a separate proxy process, but this would permit it in
the _same_ process without anything getting confused.)
I've centralised a full set of stub methods in misc.c for the new
abstraction, which allows me to get rid of several annoying stubs in
the previous code. Also, while I'm here, I've moved a lot of
duplicated modalfatalbox() type functions from application main
program files into wincons.c / uxcons.c, which I think saves
duplication overall. (A minor visible effect is that the prefixes on
those console-based fatal error messages will now be more consistent
between applications.)
2018-10-11 18:58:42 +00:00
|
|
|
* seat_get_userpass_input() failed to get a username.
|
Move most of ssh.c out into separate source files.
I've tried to separate out as many individually coherent changes from
this work as I could into their own commits, but here's where I run
out and have to commit the rest of this major refactoring as a
big-bang change.
Most of ssh.c is now no longer in ssh.c: all five of the main
coroutines that handle layers of the SSH-1 and SSH-2 protocols now
each have their own source file to live in, and a lot of the
supporting functions have moved into the appropriate one of those too.
The new abstraction is a vtable called 'PacketProtocolLayer', which
has an input and output packet queue. Each layer's main coroutine is
invoked from the method ssh_ppl_process_queue(), which is usually
(though not exclusively) triggered automatically when things are
pushed on the input queue. In SSH-2, the base layer is the transport
protocol, and it contains a pair of subsidiary queues by which it
passes some of its packets to the higher SSH-2 layers - first userauth
and then connection, which are peers at the same level, with the
former abdicating in favour of the latter at the appropriate moment.
SSH-1 is simpler: the whole login phase of the protocol (crypto setup
and authentication) is all in one module, and since SSH-1 has no
repeat key exchange, that setup layer abdicates in favour of the
connection phase when it's done.
ssh.c itself is now about a tenth of its old size (which all by itself
is cause for celebration!). Its main job is to set up all the layers,
hook them up to each other and to the BPP, and to funnel data back and
forth between that collection of modules and external things such as
the network and the terminal. Once it's set up a collection of packet
protocol layers, it communicates with them partly by calling methods
of the base layer (and if that's ssh2transport then it will delegate
some functionality to the corresponding methods of its higher layer),
and partly by talking directly to the connection layer no matter where
it is in the stack by means of the separate ConnectionLayer vtable
which I introduced in commit 8001dd4cb, and to which I've now added
quite a few extra methods replacing services that used to be internal
function calls within ssh.c.
(One effect of this is that the SSH-1 and SSH-2 channel storage is now
no longer shared - there are distinct struct types ssh1_channel and
ssh2_channel. That means a bit more code duplication, but on the plus
side, a lot fewer confusing conditionals in the middle of half-shared
functions, and less risk of a piece of SSH-1 escaping into SSH-2 or
vice versa, which I remember has happened at least once in the past.)
The bulk of this commit introduces the five new source files, their
common header sshppl.h and some shared supporting routines in
sshcommon.c, and rewrites nearly all of ssh.c itself. But it also
includes a couple of other changes that I couldn't separate easily
enough:
Firstly, there's a new handling for socket EOF, in which ssh.c sets an
'input_eof' flag in the BPP, and that responds by checking a flag that
tells it whether to report the EOF as an error or not. (This is the
main reason for those new BPP_READ / BPP_WAITFOR macros - they can
check the EOF flag every time the coroutine is resumed.)
Secondly, the error reporting itself is changed around again. I'd
expected to put some data fields in the public PacketProtocolLayer
structure that it could set to report errors in the same way as the
BPPs have been doing, but in the end, I decided propagating all those
data fields around was a pain and that even the BPPs shouldn't have
been doing it that way. So I've reverted to a system where everything
calls back to functions in ssh.c itself to report any connection-
ending condition. But there's a new family of those functions,
categorising the possible such conditions by semantics, and each one
has a different set of detailed effects (e.g. how rudely to close the
network connection, what exit status should be passed back to the
whole application, whether to send a disconnect message and/or display
a GUI error box).
I don't expect this to be immediately perfect: of course, the code has
been through a big upheaval, new bugs are expected, and I haven't been
able to do a full job of testing (e.g. I haven't tested every auth or
kex method). But I've checked that it _basically_ works - both SSH
protocols, all the different kinds of forwarding channel, more than
one auth method, Windows and Linux, connection sharing - and I think
it's now at the point where the easiest way to find further bugs is to
let it out into the wild and see what users can spot.
2018-09-24 17:28:16 +00:00
|
|
|
* Terminate.
|
|
|
|
*/
|
|
|
|
free_prompts(s->cur_prompt);
|
|
|
|
ssh_user_close(s->ppl.ssh, "No username provided");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
s->username = dupstr(s->cur_prompt->prompts[0]->result);
|
|
|
|
free_prompts(s->cur_prompt);
|
|
|
|
} else {
|
|
|
|
if ((flags & FLAG_VERBOSE) || (flags & FLAG_INTERACTIVE))
|
|
|
|
ppl_printf(("Using username \"%s\".\r\n", s->username));
|
|
|
|
}
|
|
|
|
s->got_username = TRUE;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Send an authentication request using method "none": (a)
|
|
|
|
* just in case it succeeds, and (b) so that we know what
|
|
|
|
* authentication methods we can usefully try next.
|
|
|
|
*/
|
|
|
|
s->ppl.bpp->pls->actx = SSH2_PKTCTX_NOAUTH;
|
|
|
|
|
|
|
|
s->pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH2_MSG_USERAUTH_REQUEST);
|
|
|
|
put_stringz(s->pktout, s->username);
|
2018-10-09 17:11:17 +00:00
|
|
|
put_stringz(s->pktout, s->successor_layer->vt->name);
|
Move most of ssh.c out into separate source files.
I've tried to separate out as many individually coherent changes from
this work as I could into their own commits, but here's where I run
out and have to commit the rest of this major refactoring as a
big-bang change.
Most of ssh.c is now no longer in ssh.c: all five of the main
coroutines that handle layers of the SSH-1 and SSH-2 protocols now
each have their own source file to live in, and a lot of the
supporting functions have moved into the appropriate one of those too.
The new abstraction is a vtable called 'PacketProtocolLayer', which
has an input and output packet queue. Each layer's main coroutine is
invoked from the method ssh_ppl_process_queue(), which is usually
(though not exclusively) triggered automatically when things are
pushed on the input queue. In SSH-2, the base layer is the transport
protocol, and it contains a pair of subsidiary queues by which it
passes some of its packets to the higher SSH-2 layers - first userauth
and then connection, which are peers at the same level, with the
former abdicating in favour of the latter at the appropriate moment.
SSH-1 is simpler: the whole login phase of the protocol (crypto setup
and authentication) is all in one module, and since SSH-1 has no
repeat key exchange, that setup layer abdicates in favour of the
connection phase when it's done.
ssh.c itself is now about a tenth of its old size (which all by itself
is cause for celebration!). Its main job is to set up all the layers,
hook them up to each other and to the BPP, and to funnel data back and
forth between that collection of modules and external things such as
the network and the terminal. Once it's set up a collection of packet
protocol layers, it communicates with them partly by calling methods
of the base layer (and if that's ssh2transport then it will delegate
some functionality to the corresponding methods of its higher layer),
and partly by talking directly to the connection layer no matter where
it is in the stack by means of the separate ConnectionLayer vtable
which I introduced in commit 8001dd4cb, and to which I've now added
quite a few extra methods replacing services that used to be internal
function calls within ssh.c.
(One effect of this is that the SSH-1 and SSH-2 channel storage is now
no longer shared - there are distinct struct types ssh1_channel and
ssh2_channel. That means a bit more code duplication, but on the plus
side, a lot fewer confusing conditionals in the middle of half-shared
functions, and less risk of a piece of SSH-1 escaping into SSH-2 or
vice versa, which I remember has happened at least once in the past.)
The bulk of this commit introduces the five new source files, their
common header sshppl.h and some shared supporting routines in
sshcommon.c, and rewrites nearly all of ssh.c itself. But it also
includes a couple of other changes that I couldn't separate easily
enough:
Firstly, there's a new handling for socket EOF, in which ssh.c sets an
'input_eof' flag in the BPP, and that responds by checking a flag that
tells it whether to report the EOF as an error or not. (This is the
main reason for those new BPP_READ / BPP_WAITFOR macros - they can
check the EOF flag every time the coroutine is resumed.)
Secondly, the error reporting itself is changed around again. I'd
expected to put some data fields in the public PacketProtocolLayer
structure that it could set to report errors in the same way as the
BPPs have been doing, but in the end, I decided propagating all those
data fields around was a pain and that even the BPPs shouldn't have
been doing it that way. So I've reverted to a system where everything
calls back to functions in ssh.c itself to report any connection-
ending condition. But there's a new family of those functions,
categorising the possible such conditions by semantics, and each one
has a different set of detailed effects (e.g. how rudely to close the
network connection, what exit status should be passed back to the
whole application, whether to send a disconnect message and/or display
a GUI error box).
I don't expect this to be immediately perfect: of course, the code has
been through a big upheaval, new bugs are expected, and I haven't been
able to do a full job of testing (e.g. I haven't tested every auth or
kex method). But I've checked that it _basically_ works - both SSH
protocols, all the different kinds of forwarding channel, more than
one auth method, Windows and Linux, connection sharing - and I think
it's now at the point where the easiest way to find further bugs is to
let it out into the wild and see what users can spot.
2018-09-24 17:28:16 +00:00
|
|
|
put_stringz(s->pktout, "none"); /* method */
|
|
|
|
pq_push(s->ppl.out_pq, s->pktout);
|
|
|
|
s->type = AUTH_TYPE_NONE;
|
|
|
|
|
|
|
|
s->tried_pubkey_config = FALSE;
|
|
|
|
s->kbd_inter_refused = FALSE;
|
|
|
|
|
|
|
|
/* Reset agent request state. */
|
|
|
|
s->done_agent = FALSE;
|
|
|
|
if (s->agent_response.ptr) {
|
|
|
|
if (s->pkblob_pos_in_agent) {
|
|
|
|
s->asrc->pos = s->pkblob_pos_in_agent;
|
|
|
|
} else {
|
|
|
|
s->asrc->pos = 9; /* skip length + type + key count */
|
|
|
|
s->keyi = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
ptrlen methods;
|
|
|
|
|
|
|
|
methods.ptr = "";
|
|
|
|
methods.len = 0;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Wait for the result of the last authentication request.
|
|
|
|
*/
|
|
|
|
crMaybeWaitUntilV((pktin = ssh2_userauth_pop(s)) != NULL);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Now is a convenient point to spew any banner material
|
|
|
|
* that we've accumulated. (This should ensure that when
|
|
|
|
* we exit the auth loop, we haven't any left to deal
|
|
|
|
* with.)
|
|
|
|
*/
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Don't show the banner if we're operating in
|
|
|
|
* non-verbose non-interactive mode. (It's probably
|
|
|
|
* a script, which means nobody will read the
|
|
|
|
* banner _anyway_, and moreover the printing of
|
|
|
|
* the banner will screw up processing on the
|
|
|
|
* output of (say) plink.)
|
|
|
|
*
|
|
|
|
* The banner data has been sanitised already by this
|
|
|
|
* point, so we can safely pass it straight to
|
New abstraction 'Seat', to pass to backends.
This is a new vtable-based abstraction which is passed to a backend in
place of Frontend, and it implements only the subset of the Frontend
functions needed by a backend. (Many other Frontend functions still
exist, notably the wide range of things called by terminal.c providing
platform-independent operations on the GUI terminal window.)
The purpose of making it a vtable is that this opens up the
possibility of creating a backend as an internal implementation detail
of some other activity, by providing just that one backend with a
custom Seat that implements the methods differently.
For example, this refactoring should make it feasible to directly
implement an SSH proxy type, aka the 'jump host' feature supported by
OpenSSH, aka 'open a secondary SSH session in MAINCHAN_DIRECT_TCP
mode, and then expose the main channel of that as the Socket for the
primary connection'. (Which of course you can already do by spawning
'plink -nc' as a separate proxy process, but this would permit it in
the _same_ process without anything getting confused.)
I've centralised a full set of stub methods in misc.c for the new
abstraction, which allows me to get rid of several annoying stubs in
the previous code. Also, while I'm here, I've moved a lot of
duplicated modalfatalbox() type functions from application main
program files into wincons.c / uxcons.c, which I think saves
duplication overall. (A minor visible effect is that the prefixes on
those console-based fatal error messages will now be more consistent
between applications.)
2018-10-11 18:58:42 +00:00
|
|
|
* seat_stderr.
|
Move most of ssh.c out into separate source files.
I've tried to separate out as many individually coherent changes from
this work as I could into their own commits, but here's where I run
out and have to commit the rest of this major refactoring as a
big-bang change.
Most of ssh.c is now no longer in ssh.c: all five of the main
coroutines that handle layers of the SSH-1 and SSH-2 protocols now
each have their own source file to live in, and a lot of the
supporting functions have moved into the appropriate one of those too.
The new abstraction is a vtable called 'PacketProtocolLayer', which
has an input and output packet queue. Each layer's main coroutine is
invoked from the method ssh_ppl_process_queue(), which is usually
(though not exclusively) triggered automatically when things are
pushed on the input queue. In SSH-2, the base layer is the transport
protocol, and it contains a pair of subsidiary queues by which it
passes some of its packets to the higher SSH-2 layers - first userauth
and then connection, which are peers at the same level, with the
former abdicating in favour of the latter at the appropriate moment.
SSH-1 is simpler: the whole login phase of the protocol (crypto setup
and authentication) is all in one module, and since SSH-1 has no
repeat key exchange, that setup layer abdicates in favour of the
connection phase when it's done.
ssh.c itself is now about a tenth of its old size (which all by itself
is cause for celebration!). Its main job is to set up all the layers,
hook them up to each other and to the BPP, and to funnel data back and
forth between that collection of modules and external things such as
the network and the terminal. Once it's set up a collection of packet
protocol layers, it communicates with them partly by calling methods
of the base layer (and if that's ssh2transport then it will delegate
some functionality to the corresponding methods of its higher layer),
and partly by talking directly to the connection layer no matter where
it is in the stack by means of the separate ConnectionLayer vtable
which I introduced in commit 8001dd4cb, and to which I've now added
quite a few extra methods replacing services that used to be internal
function calls within ssh.c.
(One effect of this is that the SSH-1 and SSH-2 channel storage is now
no longer shared - there are distinct struct types ssh1_channel and
ssh2_channel. That means a bit more code duplication, but on the plus
side, a lot fewer confusing conditionals in the middle of half-shared
functions, and less risk of a piece of SSH-1 escaping into SSH-2 or
vice versa, which I remember has happened at least once in the past.)
The bulk of this commit introduces the five new source files, their
common header sshppl.h and some shared supporting routines in
sshcommon.c, and rewrites nearly all of ssh.c itself. But it also
includes a couple of other changes that I couldn't separate easily
enough:
Firstly, there's a new handling for socket EOF, in which ssh.c sets an
'input_eof' flag in the BPP, and that responds by checking a flag that
tells it whether to report the EOF as an error or not. (This is the
main reason for those new BPP_READ / BPP_WAITFOR macros - they can
check the EOF flag every time the coroutine is resumed.)
Secondly, the error reporting itself is changed around again. I'd
expected to put some data fields in the public PacketProtocolLayer
structure that it could set to report errors in the same way as the
BPPs have been doing, but in the end, I decided propagating all those
data fields around was a pain and that even the BPPs shouldn't have
been doing it that way. So I've reverted to a system where everything
calls back to functions in ssh.c itself to report any connection-
ending condition. But there's a new family of those functions,
categorising the possible such conditions by semantics, and each one
has a different set of detailed effects (e.g. how rudely to close the
network connection, what exit status should be passed back to the
whole application, whether to send a disconnect message and/or display
a GUI error box).
I don't expect this to be immediately perfect: of course, the code has
been through a big upheaval, new bugs are expected, and I haven't been
able to do a full job of testing (e.g. I haven't tested every auth or
kex method). But I've checked that it _basically_ works - both SSH
protocols, all the different kinds of forwarding channel, more than
one auth method, Windows and Linux, connection sharing - and I think
it's now at the point where the easiest way to find further bugs is to
let it out into the wild and see what users can spot.
2018-09-24 17:28:16 +00:00
|
|
|
*/
|
|
|
|
if (bufchain_size(&s->banner) &&
|
|
|
|
(flags & (FLAG_VERBOSE | FLAG_INTERACTIVE))) {
|
|
|
|
while (bufchain_size(&s->banner) > 0) {
|
|
|
|
void *data;
|
|
|
|
int len;
|
|
|
|
bufchain_prefix(&s->banner, &data, &len);
|
New abstraction 'Seat', to pass to backends.
This is a new vtable-based abstraction which is passed to a backend in
place of Frontend, and it implements only the subset of the Frontend
functions needed by a backend. (Many other Frontend functions still
exist, notably the wide range of things called by terminal.c providing
platform-independent operations on the GUI terminal window.)
The purpose of making it a vtable is that this opens up the
possibility of creating a backend as an internal implementation detail
of some other activity, by providing just that one backend with a
custom Seat that implements the methods differently.
For example, this refactoring should make it feasible to directly
implement an SSH proxy type, aka the 'jump host' feature supported by
OpenSSH, aka 'open a secondary SSH session in MAINCHAN_DIRECT_TCP
mode, and then expose the main channel of that as the Socket for the
primary connection'. (Which of course you can already do by spawning
'plink -nc' as a separate proxy process, but this would permit it in
the _same_ process without anything getting confused.)
I've centralised a full set of stub methods in misc.c for the new
abstraction, which allows me to get rid of several annoying stubs in
the previous code. Also, while I'm here, I've moved a lot of
duplicated modalfatalbox() type functions from application main
program files into wincons.c / uxcons.c, which I think saves
duplication overall. (A minor visible effect is that the prefixes on
those console-based fatal error messages will now be more consistent
between applications.)
2018-10-11 18:58:42 +00:00
|
|
|
seat_stderr(s->ppl.seat, data, len);
|
Move most of ssh.c out into separate source files.
I've tried to separate out as many individually coherent changes from
this work as I could into their own commits, but here's where I run
out and have to commit the rest of this major refactoring as a
big-bang change.
Most of ssh.c is now no longer in ssh.c: all five of the main
coroutines that handle layers of the SSH-1 and SSH-2 protocols now
each have their own source file to live in, and a lot of the
supporting functions have moved into the appropriate one of those too.
The new abstraction is a vtable called 'PacketProtocolLayer', which
has an input and output packet queue. Each layer's main coroutine is
invoked from the method ssh_ppl_process_queue(), which is usually
(though not exclusively) triggered automatically when things are
pushed on the input queue. In SSH-2, the base layer is the transport
protocol, and it contains a pair of subsidiary queues by which it
passes some of its packets to the higher SSH-2 layers - first userauth
and then connection, which are peers at the same level, with the
former abdicating in favour of the latter at the appropriate moment.
SSH-1 is simpler: the whole login phase of the protocol (crypto setup
and authentication) is all in one module, and since SSH-1 has no
repeat key exchange, that setup layer abdicates in favour of the
connection phase when it's done.
ssh.c itself is now about a tenth of its old size (which all by itself
is cause for celebration!). Its main job is to set up all the layers,
hook them up to each other and to the BPP, and to funnel data back and
forth between that collection of modules and external things such as
the network and the terminal. Once it's set up a collection of packet
protocol layers, it communicates with them partly by calling methods
of the base layer (and if that's ssh2transport then it will delegate
some functionality to the corresponding methods of its higher layer),
and partly by talking directly to the connection layer no matter where
it is in the stack by means of the separate ConnectionLayer vtable
which I introduced in commit 8001dd4cb, and to which I've now added
quite a few extra methods replacing services that used to be internal
function calls within ssh.c.
(One effect of this is that the SSH-1 and SSH-2 channel storage is now
no longer shared - there are distinct struct types ssh1_channel and
ssh2_channel. That means a bit more code duplication, but on the plus
side, a lot fewer confusing conditionals in the middle of half-shared
functions, and less risk of a piece of SSH-1 escaping into SSH-2 or
vice versa, which I remember has happened at least once in the past.)
The bulk of this commit introduces the five new source files, their
common header sshppl.h and some shared supporting routines in
sshcommon.c, and rewrites nearly all of ssh.c itself. But it also
includes a couple of other changes that I couldn't separate easily
enough:
Firstly, there's a new handling for socket EOF, in which ssh.c sets an
'input_eof' flag in the BPP, and that responds by checking a flag that
tells it whether to report the EOF as an error or not. (This is the
main reason for those new BPP_READ / BPP_WAITFOR macros - they can
check the EOF flag every time the coroutine is resumed.)
Secondly, the error reporting itself is changed around again. I'd
expected to put some data fields in the public PacketProtocolLayer
structure that it could set to report errors in the same way as the
BPPs have been doing, but in the end, I decided propagating all those
data fields around was a pain and that even the BPPs shouldn't have
been doing it that way. So I've reverted to a system where everything
calls back to functions in ssh.c itself to report any connection-
ending condition. But there's a new family of those functions,
categorising the possible such conditions by semantics, and each one
has a different set of detailed effects (e.g. how rudely to close the
network connection, what exit status should be passed back to the
whole application, whether to send a disconnect message and/or display
a GUI error box).
I don't expect this to be immediately perfect: of course, the code has
been through a big upheaval, new bugs are expected, and I haven't been
able to do a full job of testing (e.g. I haven't tested every auth or
kex method). But I've checked that it _basically_ works - both SSH
protocols, all the different kinds of forwarding channel, more than
one auth method, Windows and Linux, connection sharing - and I think
it's now at the point where the easiest way to find further bugs is to
let it out into the wild and see what users can spot.
2018-09-24 17:28:16 +00:00
|
|
|
bufchain_consume(&s->banner, len);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
bufchain_clear(&s->banner);
|
|
|
|
}
|
|
|
|
if (pktin->type == SSH2_MSG_USERAUTH_SUCCESS) {
|
|
|
|
ppl_logevent(("Access granted"));
|
|
|
|
goto userauth_success;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pktin->type != SSH2_MSG_USERAUTH_FAILURE &&
|
|
|
|
s->type != AUTH_TYPE_GSSAPI) {
|
|
|
|
ssh_proto_error(s->ppl.ssh, "Received unexpected packet "
|
|
|
|
"in response to authentication request, "
|
|
|
|
"type %d (%s)", pktin->type,
|
|
|
|
ssh2_pkt_type(s->ppl.bpp->pls->kctx,
|
|
|
|
s->ppl.bpp->pls->actx,
|
|
|
|
pktin->type));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* OK, we're now sitting on a USERAUTH_FAILURE message, so
|
|
|
|
* we can look at the string in it and know what we can
|
|
|
|
* helpfully try next.
|
|
|
|
*/
|
|
|
|
if (pktin->type == SSH2_MSG_USERAUTH_FAILURE) {
|
|
|
|
methods = get_string(pktin);
|
|
|
|
if (!get_bool(pktin)) {
|
|
|
|
/*
|
|
|
|
* We have received an unequivocal Access
|
|
|
|
* Denied. This can translate to a variety of
|
|
|
|
* messages, or no message at all.
|
|
|
|
*
|
|
|
|
* For forms of authentication which are attempted
|
|
|
|
* implicitly, by which I mean without printing
|
|
|
|
* anything in the window indicating that we're
|
|
|
|
* trying them, we should never print 'Access
|
|
|
|
* denied'.
|
|
|
|
*
|
|
|
|
* If we do print a message saying that we're
|
|
|
|
* attempting some kind of authentication, it's OK
|
|
|
|
* to print a followup message saying it failed -
|
|
|
|
* but the message may sometimes be more specific
|
|
|
|
* than simply 'Access denied'.
|
|
|
|
*
|
|
|
|
* Additionally, if we'd just tried password
|
|
|
|
* authentication, we should break out of this
|
|
|
|
* whole loop so as to go back to the username
|
|
|
|
* prompt (iff we're configured to allow
|
|
|
|
* username change attempts).
|
|
|
|
*/
|
|
|
|
if (s->type == AUTH_TYPE_NONE) {
|
|
|
|
/* do nothing */
|
|
|
|
} else if (s->type == AUTH_TYPE_PUBLICKEY_OFFER_LOUD ||
|
|
|
|
s->type == AUTH_TYPE_PUBLICKEY_OFFER_QUIET) {
|
|
|
|
if (s->type == AUTH_TYPE_PUBLICKEY_OFFER_LOUD)
|
|
|
|
ppl_printf(("Server refused our key\r\n"));
|
|
|
|
ppl_logevent(("Server refused our key"));
|
|
|
|
} else if (s->type == AUTH_TYPE_PUBLICKEY) {
|
|
|
|
/* This _shouldn't_ happen except by a
|
|
|
|
* protocol bug causing client and server to
|
|
|
|
* disagree on what is a correct signature. */
|
|
|
|
ppl_printf(("Server refused public-key signature"
|
|
|
|
" despite accepting key!\r\n"));
|
|
|
|
ppl_logevent(("Server refused public-key signature"
|
|
|
|
" despite accepting key!"));
|
|
|
|
} else if (s->type==AUTH_TYPE_KEYBOARD_INTERACTIVE_QUIET) {
|
|
|
|
/* quiet, so no ppl_printf */
|
|
|
|
ppl_logevent(("Server refused keyboard-interactive "
|
|
|
|
"authentication"));
|
|
|
|
} else if (s->type==AUTH_TYPE_GSSAPI) {
|
|
|
|
/* always quiet, so no ppl_printf */
|
|
|
|
/* also, the code down in the GSSAPI block has
|
|
|
|
* already logged this in the Event Log */
|
|
|
|
} else if (s->type == AUTH_TYPE_KEYBOARD_INTERACTIVE) {
|
|
|
|
ppl_logevent(("Keyboard-interactive authentication "
|
|
|
|
"failed"));
|
|
|
|
ppl_printf(("Access denied\r\n"));
|
|
|
|
} else {
|
|
|
|
assert(s->type == AUTH_TYPE_PASSWORD);
|
|
|
|
ppl_logevent(("Password authentication failed"));
|
|
|
|
ppl_printf(("Access denied\r\n"));
|
|
|
|
|
|
|
|
if (s->change_username) {
|
|
|
|
/* XXX perhaps we should allow
|
|
|
|
* keyboard-interactive to do this too? */
|
|
|
|
goto try_new_username;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
ppl_printf(("Further authentication required\r\n"));
|
|
|
|
ppl_logevent(("Further authentication required"));
|
|
|
|
}
|
|
|
|
|
|
|
|
s->can_pubkey =
|
|
|
|
in_commasep_string("publickey", methods.ptr, methods.len);
|
|
|
|
s->can_passwd =
|
|
|
|
in_commasep_string("password", methods.ptr, methods.len);
|
|
|
|
s->can_keyb_inter =
|
|
|
|
s->try_ki_auth &&
|
|
|
|
in_commasep_string("keyboard-interactive",
|
|
|
|
methods.ptr, methods.len);
|
|
|
|
#ifndef NO_GSSAPI
|
|
|
|
s->can_gssapi =
|
|
|
|
s->try_gssapi_auth &&
|
|
|
|
in_commasep_string("gssapi-with-mic",
|
|
|
|
methods.ptr, methods.len) &&
|
|
|
|
s->shgss->libs->nlibraries > 0;
|
|
|
|
s->can_gssapi_keyex_auth =
|
|
|
|
s->try_gssapi_kex_auth &&
|
|
|
|
in_commasep_string("gssapi-keyex",
|
|
|
|
methods.ptr, methods.len) &&
|
|
|
|
s->shgss->libs->nlibraries > 0 &&
|
|
|
|
s->shgss->ctx;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
s->ppl.bpp->pls->actx = SSH2_PKTCTX_NOAUTH;
|
|
|
|
|
|
|
|
#ifndef NO_GSSAPI
|
|
|
|
if (s->can_gssapi_keyex_auth && !s->tried_gssapi_keyex_auth) {
|
|
|
|
|
|
|
|
/* gssapi-keyex authentication */
|
|
|
|
|
|
|
|
s->type = AUTH_TYPE_GSSAPI;
|
|
|
|
s->tried_gssapi_keyex_auth = TRUE;
|
|
|
|
s->ppl.bpp->pls->actx = SSH2_PKTCTX_GSSAPI;
|
|
|
|
|
|
|
|
if (s->shgss->lib->gsslogmsg)
|
|
|
|
ppl_logevent(("%s", s->shgss->lib->gsslogmsg));
|
|
|
|
|
|
|
|
ppl_logevent(("Trying gssapi-keyex..."));
|
|
|
|
s->pktout = ssh2_userauth_gss_packet(s, "gssapi-keyex");
|
|
|
|
pq_push(s->ppl.out_pq, s->pktout);
|
|
|
|
s->shgss->lib->release_cred(s->shgss->lib, &s->shgss->ctx);
|
|
|
|
s->shgss->ctx = NULL;
|
|
|
|
|
|
|
|
continue;
|
|
|
|
} else
|
|
|
|
#endif /* NO_GSSAPI */
|
|
|
|
|
|
|
|
if (s->can_pubkey && !s->done_agent && s->nkeys) {
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Attempt public-key authentication using a key from Pageant.
|
|
|
|
*/
|
|
|
|
|
|
|
|
s->ppl.bpp->pls->actx = SSH2_PKTCTX_PUBLICKEY;
|
|
|
|
|
|
|
|
ppl_logevent(("Trying Pageant key #%d", s->keyi));
|
|
|
|
|
|
|
|
/* Unpack key from agent response */
|
|
|
|
s->pk = get_string(s->asrc);
|
|
|
|
s->comment = get_string(s->asrc);
|
|
|
|
{
|
|
|
|
BinarySource src[1];
|
|
|
|
BinarySource_BARE_INIT(src, s->pk.ptr, s->pk.len);
|
|
|
|
s->alg = get_string(src);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* See if server will accept it */
|
|
|
|
s->pktout = ssh_bpp_new_pktout(
|
|
|
|
s->ppl.bpp, SSH2_MSG_USERAUTH_REQUEST);
|
|
|
|
put_stringz(s->pktout, s->username);
|
2018-10-09 17:11:17 +00:00
|
|
|
put_stringz(s->pktout, s->successor_layer->vt->name);
|
Move most of ssh.c out into separate source files.
I've tried to separate out as many individually coherent changes from
this work as I could into their own commits, but here's where I run
out and have to commit the rest of this major refactoring as a
big-bang change.
Most of ssh.c is now no longer in ssh.c: all five of the main
coroutines that handle layers of the SSH-1 and SSH-2 protocols now
each have their own source file to live in, and a lot of the
supporting functions have moved into the appropriate one of those too.
The new abstraction is a vtable called 'PacketProtocolLayer', which
has an input and output packet queue. Each layer's main coroutine is
invoked from the method ssh_ppl_process_queue(), which is usually
(though not exclusively) triggered automatically when things are
pushed on the input queue. In SSH-2, the base layer is the transport
protocol, and it contains a pair of subsidiary queues by which it
passes some of its packets to the higher SSH-2 layers - first userauth
and then connection, which are peers at the same level, with the
former abdicating in favour of the latter at the appropriate moment.
SSH-1 is simpler: the whole login phase of the protocol (crypto setup
and authentication) is all in one module, and since SSH-1 has no
repeat key exchange, that setup layer abdicates in favour of the
connection phase when it's done.
ssh.c itself is now about a tenth of its old size (which all by itself
is cause for celebration!). Its main job is to set up all the layers,
hook them up to each other and to the BPP, and to funnel data back and
forth between that collection of modules and external things such as
the network and the terminal. Once it's set up a collection of packet
protocol layers, it communicates with them partly by calling methods
of the base layer (and if that's ssh2transport then it will delegate
some functionality to the corresponding methods of its higher layer),
and partly by talking directly to the connection layer no matter where
it is in the stack by means of the separate ConnectionLayer vtable
which I introduced in commit 8001dd4cb, and to which I've now added
quite a few extra methods replacing services that used to be internal
function calls within ssh.c.
(One effect of this is that the SSH-1 and SSH-2 channel storage is now
no longer shared - there are distinct struct types ssh1_channel and
ssh2_channel. That means a bit more code duplication, but on the plus
side, a lot fewer confusing conditionals in the middle of half-shared
functions, and less risk of a piece of SSH-1 escaping into SSH-2 or
vice versa, which I remember has happened at least once in the past.)
The bulk of this commit introduces the five new source files, their
common header sshppl.h and some shared supporting routines in
sshcommon.c, and rewrites nearly all of ssh.c itself. But it also
includes a couple of other changes that I couldn't separate easily
enough:
Firstly, there's a new handling for socket EOF, in which ssh.c sets an
'input_eof' flag in the BPP, and that responds by checking a flag that
tells it whether to report the EOF as an error or not. (This is the
main reason for those new BPP_READ / BPP_WAITFOR macros - they can
check the EOF flag every time the coroutine is resumed.)
Secondly, the error reporting itself is changed around again. I'd
expected to put some data fields in the public PacketProtocolLayer
structure that it could set to report errors in the same way as the
BPPs have been doing, but in the end, I decided propagating all those
data fields around was a pain and that even the BPPs shouldn't have
been doing it that way. So I've reverted to a system where everything
calls back to functions in ssh.c itself to report any connection-
ending condition. But there's a new family of those functions,
categorising the possible such conditions by semantics, and each one
has a different set of detailed effects (e.g. how rudely to close the
network connection, what exit status should be passed back to the
whole application, whether to send a disconnect message and/or display
a GUI error box).
I don't expect this to be immediately perfect: of course, the code has
been through a big upheaval, new bugs are expected, and I haven't been
able to do a full job of testing (e.g. I haven't tested every auth or
kex method). But I've checked that it _basically_ works - both SSH
protocols, all the different kinds of forwarding channel, more than
one auth method, Windows and Linux, connection sharing - and I think
it's now at the point where the easiest way to find further bugs is to
let it out into the wild and see what users can spot.
2018-09-24 17:28:16 +00:00
|
|
|
put_stringz(s->pktout, "publickey");
|
|
|
|
/* method */
|
|
|
|
put_bool(s->pktout, FALSE); /* no signature included */
|
|
|
|
put_stringpl(s->pktout, s->alg);
|
|
|
|
put_stringpl(s->pktout, s->pk);
|
|
|
|
pq_push(s->ppl.out_pq, s->pktout);
|
|
|
|
s->type = AUTH_TYPE_PUBLICKEY_OFFER_QUIET;
|
|
|
|
|
|
|
|
crMaybeWaitUntilV((pktin = ssh2_userauth_pop(s)) != NULL);
|
|
|
|
if (pktin->type != SSH2_MSG_USERAUTH_PK_OK) {
|
|
|
|
|
|
|
|
/* Offer of key refused, presumably via
|
|
|
|
* USERAUTH_FAILURE. Requeue for the next iteration. */
|
|
|
|
pq_push_front(s->ppl.in_pq, pktin);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
strbuf *agentreq, *sigdata;
|
|
|
|
|
|
|
|
if (flags & FLAG_VERBOSE)
|
|
|
|
ppl_printf(("Authenticating with public key "
|
|
|
|
"\"%.*s\" from agent\r\n",
|
|
|
|
PTRLEN_PRINTF(s->comment)));
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Server is willing to accept the key.
|
|
|
|
* Construct a SIGN_REQUEST.
|
|
|
|
*/
|
|
|
|
s->pktout = ssh_bpp_new_pktout(
|
|
|
|
s->ppl.bpp, SSH2_MSG_USERAUTH_REQUEST);
|
|
|
|
put_stringz(s->pktout, s->username);
|
2018-10-09 17:11:17 +00:00
|
|
|
put_stringz(s->pktout, s->successor_layer->vt->name);
|
Move most of ssh.c out into separate source files.
I've tried to separate out as many individually coherent changes from
this work as I could into their own commits, but here's where I run
out and have to commit the rest of this major refactoring as a
big-bang change.
Most of ssh.c is now no longer in ssh.c: all five of the main
coroutines that handle layers of the SSH-1 and SSH-2 protocols now
each have their own source file to live in, and a lot of the
supporting functions have moved into the appropriate one of those too.
The new abstraction is a vtable called 'PacketProtocolLayer', which
has an input and output packet queue. Each layer's main coroutine is
invoked from the method ssh_ppl_process_queue(), which is usually
(though not exclusively) triggered automatically when things are
pushed on the input queue. In SSH-2, the base layer is the transport
protocol, and it contains a pair of subsidiary queues by which it
passes some of its packets to the higher SSH-2 layers - first userauth
and then connection, which are peers at the same level, with the
former abdicating in favour of the latter at the appropriate moment.
SSH-1 is simpler: the whole login phase of the protocol (crypto setup
and authentication) is all in one module, and since SSH-1 has no
repeat key exchange, that setup layer abdicates in favour of the
connection phase when it's done.
ssh.c itself is now about a tenth of its old size (which all by itself
is cause for celebration!). Its main job is to set up all the layers,
hook them up to each other and to the BPP, and to funnel data back and
forth between that collection of modules and external things such as
the network and the terminal. Once it's set up a collection of packet
protocol layers, it communicates with them partly by calling methods
of the base layer (and if that's ssh2transport then it will delegate
some functionality to the corresponding methods of its higher layer),
and partly by talking directly to the connection layer no matter where
it is in the stack by means of the separate ConnectionLayer vtable
which I introduced in commit 8001dd4cb, and to which I've now added
quite a few extra methods replacing services that used to be internal
function calls within ssh.c.
(One effect of this is that the SSH-1 and SSH-2 channel storage is now
no longer shared - there are distinct struct types ssh1_channel and
ssh2_channel. That means a bit more code duplication, but on the plus
side, a lot fewer confusing conditionals in the middle of half-shared
functions, and less risk of a piece of SSH-1 escaping into SSH-2 or
vice versa, which I remember has happened at least once in the past.)
The bulk of this commit introduces the five new source files, their
common header sshppl.h and some shared supporting routines in
sshcommon.c, and rewrites nearly all of ssh.c itself. But it also
includes a couple of other changes that I couldn't separate easily
enough:
Firstly, there's a new handling for socket EOF, in which ssh.c sets an
'input_eof' flag in the BPP, and that responds by checking a flag that
tells it whether to report the EOF as an error or not. (This is the
main reason for those new BPP_READ / BPP_WAITFOR macros - they can
check the EOF flag every time the coroutine is resumed.)
Secondly, the error reporting itself is changed around again. I'd
expected to put some data fields in the public PacketProtocolLayer
structure that it could set to report errors in the same way as the
BPPs have been doing, but in the end, I decided propagating all those
data fields around was a pain and that even the BPPs shouldn't have
been doing it that way. So I've reverted to a system where everything
calls back to functions in ssh.c itself to report any connection-
ending condition. But there's a new family of those functions,
categorising the possible such conditions by semantics, and each one
has a different set of detailed effects (e.g. how rudely to close the
network connection, what exit status should be passed back to the
whole application, whether to send a disconnect message and/or display
a GUI error box).
I don't expect this to be immediately perfect: of course, the code has
been through a big upheaval, new bugs are expected, and I haven't been
able to do a full job of testing (e.g. I haven't tested every auth or
kex method). But I've checked that it _basically_ works - both SSH
protocols, all the different kinds of forwarding channel, more than
one auth method, Windows and Linux, connection sharing - and I think
it's now at the point where the easiest way to find further bugs is to
let it out into the wild and see what users can spot.
2018-09-24 17:28:16 +00:00
|
|
|
put_stringz(s->pktout, "publickey");
|
|
|
|
/* method */
|
|
|
|
put_bool(s->pktout, TRUE); /* signature included */
|
|
|
|
put_stringpl(s->pktout, s->alg);
|
|
|
|
put_stringpl(s->pktout, s->pk);
|
|
|
|
|
|
|
|
/* Ask agent for signature. */
|
|
|
|
agentreq = strbuf_new_for_agent_query();
|
|
|
|
put_byte(agentreq, SSH2_AGENTC_SIGN_REQUEST);
|
|
|
|
put_stringpl(agentreq, s->pk);
|
|
|
|
/* Now the data to be signed... */
|
|
|
|
sigdata = strbuf_new();
|
|
|
|
ssh2_userauth_add_session_id(s, sigdata);
|
|
|
|
put_data(sigdata, s->pktout->data + 5,
|
|
|
|
s->pktout->length - 5);
|
|
|
|
put_stringsb(agentreq, sigdata);
|
|
|
|
/* And finally the (zero) flags word. */
|
|
|
|
put_uint32(agentreq, 0);
|
|
|
|
ssh2_userauth_agent_query(s, agentreq);
|
|
|
|
strbuf_free(agentreq);
|
|
|
|
crWaitUntilV(!s->auth_agent_query);
|
|
|
|
|
|
|
|
if (s->agent_response.ptr) {
|
|
|
|
ptrlen sigblob;
|
|
|
|
BinarySource src[1];
|
|
|
|
BinarySource_BARE_INIT(src, s->agent_response.ptr,
|
|
|
|
s->agent_response.len);
|
|
|
|
get_uint32(src); /* skip length field */
|
|
|
|
if (get_byte(src) == SSH2_AGENT_SIGN_RESPONSE &&
|
|
|
|
(sigblob = get_string(src), !get_err(src))) {
|
|
|
|
ppl_logevent(("Sending Pageant's response"));
|
|
|
|
ssh2_userauth_add_sigblob(s, s->pktout,
|
|
|
|
s->pk, sigblob);
|
|
|
|
pq_push(s->ppl.out_pq, s->pktout);
|
|
|
|
s->type = AUTH_TYPE_PUBLICKEY;
|
|
|
|
} else {
|
|
|
|
/* FIXME: less drastic response */
|
|
|
|
ssh_sw_abort(s->ppl.ssh, "Pageant failed to "
|
|
|
|
"provide a signature");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Do we have any keys left to try? */
|
|
|
|
if (s->pkblob_pos_in_agent) {
|
|
|
|
s->done_agent = TRUE;
|
|
|
|
s->tried_pubkey_config = TRUE;
|
|
|
|
} else {
|
|
|
|
s->keyi++;
|
|
|
|
if (s->keyi >= s->nkeys)
|
|
|
|
s->done_agent = TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
} else if (s->can_pubkey && s->publickey_blob &&
|
|
|
|
s->privatekey_available && !s->tried_pubkey_config) {
|
|
|
|
|
|
|
|
struct ssh2_userkey *key; /* not live over crReturn */
|
|
|
|
char *passphrase; /* not live over crReturn */
|
|
|
|
|
|
|
|
s->ppl.bpp->pls->actx = SSH2_PKTCTX_PUBLICKEY;
|
|
|
|
|
|
|
|
s->tried_pubkey_config = TRUE;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Try the public key supplied in the configuration.
|
|
|
|
*
|
|
|
|
* First, offer the public blob to see if the server is
|
|
|
|
* willing to accept it.
|
|
|
|
*/
|
|
|
|
s->pktout = ssh_bpp_new_pktout(
|
|
|
|
s->ppl.bpp, SSH2_MSG_USERAUTH_REQUEST);
|
|
|
|
put_stringz(s->pktout, s->username);
|
2018-10-09 17:11:17 +00:00
|
|
|
put_stringz(s->pktout, s->successor_layer->vt->name);
|
Move most of ssh.c out into separate source files.
I've tried to separate out as many individually coherent changes from
this work as I could into their own commits, but here's where I run
out and have to commit the rest of this major refactoring as a
big-bang change.
Most of ssh.c is now no longer in ssh.c: all five of the main
coroutines that handle layers of the SSH-1 and SSH-2 protocols now
each have their own source file to live in, and a lot of the
supporting functions have moved into the appropriate one of those too.
The new abstraction is a vtable called 'PacketProtocolLayer', which
has an input and output packet queue. Each layer's main coroutine is
invoked from the method ssh_ppl_process_queue(), which is usually
(though not exclusively) triggered automatically when things are
pushed on the input queue. In SSH-2, the base layer is the transport
protocol, and it contains a pair of subsidiary queues by which it
passes some of its packets to the higher SSH-2 layers - first userauth
and then connection, which are peers at the same level, with the
former abdicating in favour of the latter at the appropriate moment.
SSH-1 is simpler: the whole login phase of the protocol (crypto setup
and authentication) is all in one module, and since SSH-1 has no
repeat key exchange, that setup layer abdicates in favour of the
connection phase when it's done.
ssh.c itself is now about a tenth of its old size (which all by itself
is cause for celebration!). Its main job is to set up all the layers,
hook them up to each other and to the BPP, and to funnel data back and
forth between that collection of modules and external things such as
the network and the terminal. Once it's set up a collection of packet
protocol layers, it communicates with them partly by calling methods
of the base layer (and if that's ssh2transport then it will delegate
some functionality to the corresponding methods of its higher layer),
and partly by talking directly to the connection layer no matter where
it is in the stack by means of the separate ConnectionLayer vtable
which I introduced in commit 8001dd4cb, and to which I've now added
quite a few extra methods replacing services that used to be internal
function calls within ssh.c.
(One effect of this is that the SSH-1 and SSH-2 channel storage is now
no longer shared - there are distinct struct types ssh1_channel and
ssh2_channel. That means a bit more code duplication, but on the plus
side, a lot fewer confusing conditionals in the middle of half-shared
functions, and less risk of a piece of SSH-1 escaping into SSH-2 or
vice versa, which I remember has happened at least once in the past.)
The bulk of this commit introduces the five new source files, their
common header sshppl.h and some shared supporting routines in
sshcommon.c, and rewrites nearly all of ssh.c itself. But it also
includes a couple of other changes that I couldn't separate easily
enough:
Firstly, there's a new handling for socket EOF, in which ssh.c sets an
'input_eof' flag in the BPP, and that responds by checking a flag that
tells it whether to report the EOF as an error or not. (This is the
main reason for those new BPP_READ / BPP_WAITFOR macros - they can
check the EOF flag every time the coroutine is resumed.)
Secondly, the error reporting itself is changed around again. I'd
expected to put some data fields in the public PacketProtocolLayer
structure that it could set to report errors in the same way as the
BPPs have been doing, but in the end, I decided propagating all those
data fields around was a pain and that even the BPPs shouldn't have
been doing it that way. So I've reverted to a system where everything
calls back to functions in ssh.c itself to report any connection-
ending condition. But there's a new family of those functions,
categorising the possible such conditions by semantics, and each one
has a different set of detailed effects (e.g. how rudely to close the
network connection, what exit status should be passed back to the
whole application, whether to send a disconnect message and/or display
a GUI error box).
I don't expect this to be immediately perfect: of course, the code has
been through a big upheaval, new bugs are expected, and I haven't been
able to do a full job of testing (e.g. I haven't tested every auth or
kex method). But I've checked that it _basically_ works - both SSH
protocols, all the different kinds of forwarding channel, more than
one auth method, Windows and Linux, connection sharing - and I think
it's now at the point where the easiest way to find further bugs is to
let it out into the wild and see what users can spot.
2018-09-24 17:28:16 +00:00
|
|
|
put_stringz(s->pktout, "publickey"); /* method */
|
|
|
|
put_bool(s->pktout, FALSE);
|
|
|
|
/* no signature included */
|
|
|
|
put_stringz(s->pktout, s->publickey_algorithm);
|
|
|
|
put_string(s->pktout, s->publickey_blob->s,
|
|
|
|
s->publickey_blob->len);
|
|
|
|
pq_push(s->ppl.out_pq, s->pktout);
|
|
|
|
ppl_logevent(("Offered public key"));
|
|
|
|
|
|
|
|
crMaybeWaitUntilV((pktin = ssh2_userauth_pop(s)) != NULL);
|
|
|
|
if (pktin->type != SSH2_MSG_USERAUTH_PK_OK) {
|
|
|
|
/* Key refused. Give up. */
|
|
|
|
pq_push_front(s->ppl.in_pq, pktin);
|
|
|
|
s->type = AUTH_TYPE_PUBLICKEY_OFFER_LOUD;
|
|
|
|
continue; /* process this new message */
|
|
|
|
}
|
|
|
|
ppl_logevent(("Offer of public key accepted"));
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Actually attempt a serious authentication using
|
|
|
|
* the key.
|
|
|
|
*/
|
|
|
|
if (flags & FLAG_VERBOSE)
|
|
|
|
ppl_printf(("Authenticating with public key \"%s\"\r\n",
|
|
|
|
s->publickey_comment));
|
|
|
|
|
|
|
|
key = NULL;
|
|
|
|
while (!key) {
|
|
|
|
const char *error; /* not live over crReturn */
|
|
|
|
if (s->privatekey_encrypted) {
|
|
|
|
/*
|
|
|
|
* Get a passphrase from the user.
|
|
|
|
*/
|
New abstraction 'Seat', to pass to backends.
This is a new vtable-based abstraction which is passed to a backend in
place of Frontend, and it implements only the subset of the Frontend
functions needed by a backend. (Many other Frontend functions still
exist, notably the wide range of things called by terminal.c providing
platform-independent operations on the GUI terminal window.)
The purpose of making it a vtable is that this opens up the
possibility of creating a backend as an internal implementation detail
of some other activity, by providing just that one backend with a
custom Seat that implements the methods differently.
For example, this refactoring should make it feasible to directly
implement an SSH proxy type, aka the 'jump host' feature supported by
OpenSSH, aka 'open a secondary SSH session in MAINCHAN_DIRECT_TCP
mode, and then expose the main channel of that as the Socket for the
primary connection'. (Which of course you can already do by spawning
'plink -nc' as a separate proxy process, but this would permit it in
the _same_ process without anything getting confused.)
I've centralised a full set of stub methods in misc.c for the new
abstraction, which allows me to get rid of several annoying stubs in
the previous code. Also, while I'm here, I've moved a lot of
duplicated modalfatalbox() type functions from application main
program files into wincons.c / uxcons.c, which I think saves
duplication overall. (A minor visible effect is that the prefixes on
those console-based fatal error messages will now be more consistent
between applications.)
2018-10-11 18:58:42 +00:00
|
|
|
s->cur_prompt = new_prompts();
|
Move most of ssh.c out into separate source files.
I've tried to separate out as many individually coherent changes from
this work as I could into their own commits, but here's where I run
out and have to commit the rest of this major refactoring as a
big-bang change.
Most of ssh.c is now no longer in ssh.c: all five of the main
coroutines that handle layers of the SSH-1 and SSH-2 protocols now
each have their own source file to live in, and a lot of the
supporting functions have moved into the appropriate one of those too.
The new abstraction is a vtable called 'PacketProtocolLayer', which
has an input and output packet queue. Each layer's main coroutine is
invoked from the method ssh_ppl_process_queue(), which is usually
(though not exclusively) triggered automatically when things are
pushed on the input queue. In SSH-2, the base layer is the transport
protocol, and it contains a pair of subsidiary queues by which it
passes some of its packets to the higher SSH-2 layers - first userauth
and then connection, which are peers at the same level, with the
former abdicating in favour of the latter at the appropriate moment.
SSH-1 is simpler: the whole login phase of the protocol (crypto setup
and authentication) is all in one module, and since SSH-1 has no
repeat key exchange, that setup layer abdicates in favour of the
connection phase when it's done.
ssh.c itself is now about a tenth of its old size (which all by itself
is cause for celebration!). Its main job is to set up all the layers,
hook them up to each other and to the BPP, and to funnel data back and
forth between that collection of modules and external things such as
the network and the terminal. Once it's set up a collection of packet
protocol layers, it communicates with them partly by calling methods
of the base layer (and if that's ssh2transport then it will delegate
some functionality to the corresponding methods of its higher layer),
and partly by talking directly to the connection layer no matter where
it is in the stack by means of the separate ConnectionLayer vtable
which I introduced in commit 8001dd4cb, and to which I've now added
quite a few extra methods replacing services that used to be internal
function calls within ssh.c.
(One effect of this is that the SSH-1 and SSH-2 channel storage is now
no longer shared - there are distinct struct types ssh1_channel and
ssh2_channel. That means a bit more code duplication, but on the plus
side, a lot fewer confusing conditionals in the middle of half-shared
functions, and less risk of a piece of SSH-1 escaping into SSH-2 or
vice versa, which I remember has happened at least once in the past.)
The bulk of this commit introduces the five new source files, their
common header sshppl.h and some shared supporting routines in
sshcommon.c, and rewrites nearly all of ssh.c itself. But it also
includes a couple of other changes that I couldn't separate easily
enough:
Firstly, there's a new handling for socket EOF, in which ssh.c sets an
'input_eof' flag in the BPP, and that responds by checking a flag that
tells it whether to report the EOF as an error or not. (This is the
main reason for those new BPP_READ / BPP_WAITFOR macros - they can
check the EOF flag every time the coroutine is resumed.)
Secondly, the error reporting itself is changed around again. I'd
expected to put some data fields in the public PacketProtocolLayer
structure that it could set to report errors in the same way as the
BPPs have been doing, but in the end, I decided propagating all those
data fields around was a pain and that even the BPPs shouldn't have
been doing it that way. So I've reverted to a system where everything
calls back to functions in ssh.c itself to report any connection-
ending condition. But there's a new family of those functions,
categorising the possible such conditions by semantics, and each one
has a different set of detailed effects (e.g. how rudely to close the
network connection, what exit status should be passed back to the
whole application, whether to send a disconnect message and/or display
a GUI error box).
I don't expect this to be immediately perfect: of course, the code has
been through a big upheaval, new bugs are expected, and I haven't been
able to do a full job of testing (e.g. I haven't tested every auth or
kex method). But I've checked that it _basically_ works - both SSH
protocols, all the different kinds of forwarding channel, more than
one auth method, Windows and Linux, connection sharing - and I think
it's now at the point where the easiest way to find further bugs is to
let it out into the wild and see what users can spot.
2018-09-24 17:28:16 +00:00
|
|
|
s->cur_prompt->to_server = FALSE;
|
|
|
|
s->cur_prompt->name = dupstr("SSH key passphrase");
|
|
|
|
add_prompt(s->cur_prompt,
|
|
|
|
dupprintf("Passphrase for key \"%.100s\": ",
|
|
|
|
s->publickey_comment),
|
|
|
|
FALSE);
|
New abstraction 'Seat', to pass to backends.
This is a new vtable-based abstraction which is passed to a backend in
place of Frontend, and it implements only the subset of the Frontend
functions needed by a backend. (Many other Frontend functions still
exist, notably the wide range of things called by terminal.c providing
platform-independent operations on the GUI terminal window.)
The purpose of making it a vtable is that this opens up the
possibility of creating a backend as an internal implementation detail
of some other activity, by providing just that one backend with a
custom Seat that implements the methods differently.
For example, this refactoring should make it feasible to directly
implement an SSH proxy type, aka the 'jump host' feature supported by
OpenSSH, aka 'open a secondary SSH session in MAINCHAN_DIRECT_TCP
mode, and then expose the main channel of that as the Socket for the
primary connection'. (Which of course you can already do by spawning
'plink -nc' as a separate proxy process, but this would permit it in
the _same_ process without anything getting confused.)
I've centralised a full set of stub methods in misc.c for the new
abstraction, which allows me to get rid of several annoying stubs in
the previous code. Also, while I'm here, I've moved a lot of
duplicated modalfatalbox() type functions from application main
program files into wincons.c / uxcons.c, which I think saves
duplication overall. (A minor visible effect is that the prefixes on
those console-based fatal error messages will now be more consistent
between applications.)
2018-10-11 18:58:42 +00:00
|
|
|
s->userpass_ret = seat_get_userpass_input(
|
|
|
|
s->ppl.seat, s->cur_prompt, NULL);
|
Move most of ssh.c out into separate source files.
I've tried to separate out as many individually coherent changes from
this work as I could into their own commits, but here's where I run
out and have to commit the rest of this major refactoring as a
big-bang change.
Most of ssh.c is now no longer in ssh.c: all five of the main
coroutines that handle layers of the SSH-1 and SSH-2 protocols now
each have their own source file to live in, and a lot of the
supporting functions have moved into the appropriate one of those too.
The new abstraction is a vtable called 'PacketProtocolLayer', which
has an input and output packet queue. Each layer's main coroutine is
invoked from the method ssh_ppl_process_queue(), which is usually
(though not exclusively) triggered automatically when things are
pushed on the input queue. In SSH-2, the base layer is the transport
protocol, and it contains a pair of subsidiary queues by which it
passes some of its packets to the higher SSH-2 layers - first userauth
and then connection, which are peers at the same level, with the
former abdicating in favour of the latter at the appropriate moment.
SSH-1 is simpler: the whole login phase of the protocol (crypto setup
and authentication) is all in one module, and since SSH-1 has no
repeat key exchange, that setup layer abdicates in favour of the
connection phase when it's done.
ssh.c itself is now about a tenth of its old size (which all by itself
is cause for celebration!). Its main job is to set up all the layers,
hook them up to each other and to the BPP, and to funnel data back and
forth between that collection of modules and external things such as
the network and the terminal. Once it's set up a collection of packet
protocol layers, it communicates with them partly by calling methods
of the base layer (and if that's ssh2transport then it will delegate
some functionality to the corresponding methods of its higher layer),
and partly by talking directly to the connection layer no matter where
it is in the stack by means of the separate ConnectionLayer vtable
which I introduced in commit 8001dd4cb, and to which I've now added
quite a few extra methods replacing services that used to be internal
function calls within ssh.c.
(One effect of this is that the SSH-1 and SSH-2 channel storage is now
no longer shared - there are distinct struct types ssh1_channel and
ssh2_channel. That means a bit more code duplication, but on the plus
side, a lot fewer confusing conditionals in the middle of half-shared
functions, and less risk of a piece of SSH-1 escaping into SSH-2 or
vice versa, which I remember has happened at least once in the past.)
The bulk of this commit introduces the five new source files, their
common header sshppl.h and some shared supporting routines in
sshcommon.c, and rewrites nearly all of ssh.c itself. But it also
includes a couple of other changes that I couldn't separate easily
enough:
Firstly, there's a new handling for socket EOF, in which ssh.c sets an
'input_eof' flag in the BPP, and that responds by checking a flag that
tells it whether to report the EOF as an error or not. (This is the
main reason for those new BPP_READ / BPP_WAITFOR macros - they can
check the EOF flag every time the coroutine is resumed.)
Secondly, the error reporting itself is changed around again. I'd
expected to put some data fields in the public PacketProtocolLayer
structure that it could set to report errors in the same way as the
BPPs have been doing, but in the end, I decided propagating all those
data fields around was a pain and that even the BPPs shouldn't have
been doing it that way. So I've reverted to a system where everything
calls back to functions in ssh.c itself to report any connection-
ending condition. But there's a new family of those functions,
categorising the possible such conditions by semantics, and each one
has a different set of detailed effects (e.g. how rudely to close the
network connection, what exit status should be passed back to the
whole application, whether to send a disconnect message and/or display
a GUI error box).
I don't expect this to be immediately perfect: of course, the code has
been through a big upheaval, new bugs are expected, and I haven't been
able to do a full job of testing (e.g. I haven't tested every auth or
kex method). But I've checked that it _basically_ works - both SSH
protocols, all the different kinds of forwarding channel, more than
one auth method, Windows and Linux, connection sharing - and I think
it's now at the point where the easiest way to find further bugs is to
let it out into the wild and see what users can spot.
2018-09-24 17:28:16 +00:00
|
|
|
while (1) {
|
|
|
|
while (s->userpass_ret < 0 &&
|
|
|
|
bufchain_size(s->ppl.user_input) > 0)
|
New abstraction 'Seat', to pass to backends.
This is a new vtable-based abstraction which is passed to a backend in
place of Frontend, and it implements only the subset of the Frontend
functions needed by a backend. (Many other Frontend functions still
exist, notably the wide range of things called by terminal.c providing
platform-independent operations on the GUI terminal window.)
The purpose of making it a vtable is that this opens up the
possibility of creating a backend as an internal implementation detail
of some other activity, by providing just that one backend with a
custom Seat that implements the methods differently.
For example, this refactoring should make it feasible to directly
implement an SSH proxy type, aka the 'jump host' feature supported by
OpenSSH, aka 'open a secondary SSH session in MAINCHAN_DIRECT_TCP
mode, and then expose the main channel of that as the Socket for the
primary connection'. (Which of course you can already do by spawning
'plink -nc' as a separate proxy process, but this would permit it in
the _same_ process without anything getting confused.)
I've centralised a full set of stub methods in misc.c for the new
abstraction, which allows me to get rid of several annoying stubs in
the previous code. Also, while I'm here, I've moved a lot of
duplicated modalfatalbox() type functions from application main
program files into wincons.c / uxcons.c, which I think saves
duplication overall. (A minor visible effect is that the prefixes on
those console-based fatal error messages will now be more consistent
between applications.)
2018-10-11 18:58:42 +00:00
|
|
|
s->userpass_ret = seat_get_userpass_input(
|
|
|
|
s->ppl.seat, s->cur_prompt,
|
|
|
|
s->ppl.user_input);
|
Move most of ssh.c out into separate source files.
I've tried to separate out as many individually coherent changes from
this work as I could into their own commits, but here's where I run
out and have to commit the rest of this major refactoring as a
big-bang change.
Most of ssh.c is now no longer in ssh.c: all five of the main
coroutines that handle layers of the SSH-1 and SSH-2 protocols now
each have their own source file to live in, and a lot of the
supporting functions have moved into the appropriate one of those too.
The new abstraction is a vtable called 'PacketProtocolLayer', which
has an input and output packet queue. Each layer's main coroutine is
invoked from the method ssh_ppl_process_queue(), which is usually
(though not exclusively) triggered automatically when things are
pushed on the input queue. In SSH-2, the base layer is the transport
protocol, and it contains a pair of subsidiary queues by which it
passes some of its packets to the higher SSH-2 layers - first userauth
and then connection, which are peers at the same level, with the
former abdicating in favour of the latter at the appropriate moment.
SSH-1 is simpler: the whole login phase of the protocol (crypto setup
and authentication) is all in one module, and since SSH-1 has no
repeat key exchange, that setup layer abdicates in favour of the
connection phase when it's done.
ssh.c itself is now about a tenth of its old size (which all by itself
is cause for celebration!). Its main job is to set up all the layers,
hook them up to each other and to the BPP, and to funnel data back and
forth between that collection of modules and external things such as
the network and the terminal. Once it's set up a collection of packet
protocol layers, it communicates with them partly by calling methods
of the base layer (and if that's ssh2transport then it will delegate
some functionality to the corresponding methods of its higher layer),
and partly by talking directly to the connection layer no matter where
it is in the stack by means of the separate ConnectionLayer vtable
which I introduced in commit 8001dd4cb, and to which I've now added
quite a few extra methods replacing services that used to be internal
function calls within ssh.c.
(One effect of this is that the SSH-1 and SSH-2 channel storage is now
no longer shared - there are distinct struct types ssh1_channel and
ssh2_channel. That means a bit more code duplication, but on the plus
side, a lot fewer confusing conditionals in the middle of half-shared
functions, and less risk of a piece of SSH-1 escaping into SSH-2 or
vice versa, which I remember has happened at least once in the past.)
The bulk of this commit introduces the five new source files, their
common header sshppl.h and some shared supporting routines in
sshcommon.c, and rewrites nearly all of ssh.c itself. But it also
includes a couple of other changes that I couldn't separate easily
enough:
Firstly, there's a new handling for socket EOF, in which ssh.c sets an
'input_eof' flag in the BPP, and that responds by checking a flag that
tells it whether to report the EOF as an error or not. (This is the
main reason for those new BPP_READ / BPP_WAITFOR macros - they can
check the EOF flag every time the coroutine is resumed.)
Secondly, the error reporting itself is changed around again. I'd
expected to put some data fields in the public PacketProtocolLayer
structure that it could set to report errors in the same way as the
BPPs have been doing, but in the end, I decided propagating all those
data fields around was a pain and that even the BPPs shouldn't have
been doing it that way. So I've reverted to a system where everything
calls back to functions in ssh.c itself to report any connection-
ending condition. But there's a new family of those functions,
categorising the possible such conditions by semantics, and each one
has a different set of detailed effects (e.g. how rudely to close the
network connection, what exit status should be passed back to the
whole application, whether to send a disconnect message and/or display
a GUI error box).
I don't expect this to be immediately perfect: of course, the code has
been through a big upheaval, new bugs are expected, and I haven't been
able to do a full job of testing (e.g. I haven't tested every auth or
kex method). But I've checked that it _basically_ works - both SSH
protocols, all the different kinds of forwarding channel, more than
one auth method, Windows and Linux, connection sharing - and I think
it's now at the point where the easiest way to find further bugs is to
let it out into the wild and see what users can spot.
2018-09-24 17:28:16 +00:00
|
|
|
|
|
|
|
if (s->userpass_ret >= 0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
s->want_user_input = TRUE;
|
|
|
|
crReturnV;
|
|
|
|
s->want_user_input = FALSE;
|
|
|
|
}
|
|
|
|
if (!s->userpass_ret) {
|
|
|
|
/* Failed to get a passphrase. Terminate. */
|
|
|
|
free_prompts(s->cur_prompt);
|
|
|
|
ssh_bpp_queue_disconnect(
|
|
|
|
s->ppl.bpp, "Unable to authenticate",
|
|
|
|
SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER);
|
|
|
|
ssh_user_close(s->ppl.ssh, "User aborted at "
|
|
|
|
"passphrase prompt");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
passphrase =
|
|
|
|
dupstr(s->cur_prompt->prompts[0]->result);
|
|
|
|
free_prompts(s->cur_prompt);
|
|
|
|
} else {
|
|
|
|
passphrase = NULL; /* no passphrase needed */
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Try decrypting the key.
|
|
|
|
*/
|
|
|
|
key = ssh2_load_userkey(s->keyfile, passphrase, &error);
|
|
|
|
if (passphrase) {
|
|
|
|
/* burn the evidence */
|
|
|
|
smemclr(passphrase, strlen(passphrase));
|
|
|
|
sfree(passphrase);
|
|
|
|
}
|
|
|
|
if (key == SSH2_WRONG_PASSPHRASE || key == NULL) {
|
|
|
|
if (passphrase &&
|
|
|
|
(key == SSH2_WRONG_PASSPHRASE)) {
|
|
|
|
ppl_printf(("Wrong passphrase\r\n"));
|
|
|
|
key = NULL;
|
|
|
|
/* and loop again */
|
|
|
|
} else {
|
|
|
|
ppl_printf(("Unable to load private key (%s)\r\n",
|
|
|
|
error));
|
|
|
|
key = NULL;
|
|
|
|
break; /* try something else */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (key) {
|
|
|
|
strbuf *pkblob, *sigdata, *sigblob;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We have loaded the private key and the server
|
|
|
|
* has announced that it's willing to accept it.
|
|
|
|
* Hallelujah. Generate a signature and send it.
|
|
|
|
*/
|
|
|
|
s->pktout = ssh_bpp_new_pktout(
|
|
|
|
s->ppl.bpp, SSH2_MSG_USERAUTH_REQUEST);
|
|
|
|
put_stringz(s->pktout, s->username);
|
2018-10-09 17:11:17 +00:00
|
|
|
put_stringz(s->pktout, s->successor_layer->vt->name);
|
Move most of ssh.c out into separate source files.
I've tried to separate out as many individually coherent changes from
this work as I could into their own commits, but here's where I run
out and have to commit the rest of this major refactoring as a
big-bang change.
Most of ssh.c is now no longer in ssh.c: all five of the main
coroutines that handle layers of the SSH-1 and SSH-2 protocols now
each have their own source file to live in, and a lot of the
supporting functions have moved into the appropriate one of those too.
The new abstraction is a vtable called 'PacketProtocolLayer', which
has an input and output packet queue. Each layer's main coroutine is
invoked from the method ssh_ppl_process_queue(), which is usually
(though not exclusively) triggered automatically when things are
pushed on the input queue. In SSH-2, the base layer is the transport
protocol, and it contains a pair of subsidiary queues by which it
passes some of its packets to the higher SSH-2 layers - first userauth
and then connection, which are peers at the same level, with the
former abdicating in favour of the latter at the appropriate moment.
SSH-1 is simpler: the whole login phase of the protocol (crypto setup
and authentication) is all in one module, and since SSH-1 has no
repeat key exchange, that setup layer abdicates in favour of the
connection phase when it's done.
ssh.c itself is now about a tenth of its old size (which all by itself
is cause for celebration!). Its main job is to set up all the layers,
hook them up to each other and to the BPP, and to funnel data back and
forth between that collection of modules and external things such as
the network and the terminal. Once it's set up a collection of packet
protocol layers, it communicates with them partly by calling methods
of the base layer (and if that's ssh2transport then it will delegate
some functionality to the corresponding methods of its higher layer),
and partly by talking directly to the connection layer no matter where
it is in the stack by means of the separate ConnectionLayer vtable
which I introduced in commit 8001dd4cb, and to which I've now added
quite a few extra methods replacing services that used to be internal
function calls within ssh.c.
(One effect of this is that the SSH-1 and SSH-2 channel storage is now
no longer shared - there are distinct struct types ssh1_channel and
ssh2_channel. That means a bit more code duplication, but on the plus
side, a lot fewer confusing conditionals in the middle of half-shared
functions, and less risk of a piece of SSH-1 escaping into SSH-2 or
vice versa, which I remember has happened at least once in the past.)
The bulk of this commit introduces the five new source files, their
common header sshppl.h and some shared supporting routines in
sshcommon.c, and rewrites nearly all of ssh.c itself. But it also
includes a couple of other changes that I couldn't separate easily
enough:
Firstly, there's a new handling for socket EOF, in which ssh.c sets an
'input_eof' flag in the BPP, and that responds by checking a flag that
tells it whether to report the EOF as an error or not. (This is the
main reason for those new BPP_READ / BPP_WAITFOR macros - they can
check the EOF flag every time the coroutine is resumed.)
Secondly, the error reporting itself is changed around again. I'd
expected to put some data fields in the public PacketProtocolLayer
structure that it could set to report errors in the same way as the
BPPs have been doing, but in the end, I decided propagating all those
data fields around was a pain and that even the BPPs shouldn't have
been doing it that way. So I've reverted to a system where everything
calls back to functions in ssh.c itself to report any connection-
ending condition. But there's a new family of those functions,
categorising the possible such conditions by semantics, and each one
has a different set of detailed effects (e.g. how rudely to close the
network connection, what exit status should be passed back to the
whole application, whether to send a disconnect message and/or display
a GUI error box).
I don't expect this to be immediately perfect: of course, the code has
been through a big upheaval, new bugs are expected, and I haven't been
able to do a full job of testing (e.g. I haven't tested every auth or
kex method). But I've checked that it _basically_ works - both SSH
protocols, all the different kinds of forwarding channel, more than
one auth method, Windows and Linux, connection sharing - and I think
it's now at the point where the easiest way to find further bugs is to
let it out into the wild and see what users can spot.
2018-09-24 17:28:16 +00:00
|
|
|
put_stringz(s->pktout, "publickey"); /* method */
|
|
|
|
put_bool(s->pktout, TRUE); /* signature follows */
|
|
|
|
put_stringz(s->pktout, ssh_key_ssh_id(key->key));
|
|
|
|
pkblob = strbuf_new();
|
|
|
|
ssh_key_public_blob(key->key, BinarySink_UPCAST(pkblob));
|
|
|
|
put_string(s->pktout, pkblob->s, pkblob->len);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The data to be signed is:
|
|
|
|
*
|
|
|
|
* string session-id
|
|
|
|
*
|
|
|
|
* followed by everything so far placed in the
|
|
|
|
* outgoing packet.
|
|
|
|
*/
|
|
|
|
sigdata = strbuf_new();
|
|
|
|
ssh2_userauth_add_session_id(s, sigdata);
|
|
|
|
put_data(sigdata, s->pktout->data + 5,
|
|
|
|
s->pktout->length - 5);
|
|
|
|
sigblob = strbuf_new();
|
|
|
|
ssh_key_sign(key->key, sigdata->s, sigdata->len,
|
|
|
|
BinarySink_UPCAST(sigblob));
|
|
|
|
strbuf_free(sigdata);
|
|
|
|
ssh2_userauth_add_sigblob(
|
2018-10-13 15:30:59 +00:00
|
|
|
s, s->pktout, ptrlen_from_strbuf(pkblob),
|
|
|
|
ptrlen_from_strbuf(sigblob));
|
Move most of ssh.c out into separate source files.
I've tried to separate out as many individually coherent changes from
this work as I could into their own commits, but here's where I run
out and have to commit the rest of this major refactoring as a
big-bang change.
Most of ssh.c is now no longer in ssh.c: all five of the main
coroutines that handle layers of the SSH-1 and SSH-2 protocols now
each have their own source file to live in, and a lot of the
supporting functions have moved into the appropriate one of those too.
The new abstraction is a vtable called 'PacketProtocolLayer', which
has an input and output packet queue. Each layer's main coroutine is
invoked from the method ssh_ppl_process_queue(), which is usually
(though not exclusively) triggered automatically when things are
pushed on the input queue. In SSH-2, the base layer is the transport
protocol, and it contains a pair of subsidiary queues by which it
passes some of its packets to the higher SSH-2 layers - first userauth
and then connection, which are peers at the same level, with the
former abdicating in favour of the latter at the appropriate moment.
SSH-1 is simpler: the whole login phase of the protocol (crypto setup
and authentication) is all in one module, and since SSH-1 has no
repeat key exchange, that setup layer abdicates in favour of the
connection phase when it's done.
ssh.c itself is now about a tenth of its old size (which all by itself
is cause for celebration!). Its main job is to set up all the layers,
hook them up to each other and to the BPP, and to funnel data back and
forth between that collection of modules and external things such as
the network and the terminal. Once it's set up a collection of packet
protocol layers, it communicates with them partly by calling methods
of the base layer (and if that's ssh2transport then it will delegate
some functionality to the corresponding methods of its higher layer),
and partly by talking directly to the connection layer no matter where
it is in the stack by means of the separate ConnectionLayer vtable
which I introduced in commit 8001dd4cb, and to which I've now added
quite a few extra methods replacing services that used to be internal
function calls within ssh.c.
(One effect of this is that the SSH-1 and SSH-2 channel storage is now
no longer shared - there are distinct struct types ssh1_channel and
ssh2_channel. That means a bit more code duplication, but on the plus
side, a lot fewer confusing conditionals in the middle of half-shared
functions, and less risk of a piece of SSH-1 escaping into SSH-2 or
vice versa, which I remember has happened at least once in the past.)
The bulk of this commit introduces the five new source files, their
common header sshppl.h and some shared supporting routines in
sshcommon.c, and rewrites nearly all of ssh.c itself. But it also
includes a couple of other changes that I couldn't separate easily
enough:
Firstly, there's a new handling for socket EOF, in which ssh.c sets an
'input_eof' flag in the BPP, and that responds by checking a flag that
tells it whether to report the EOF as an error or not. (This is the
main reason for those new BPP_READ / BPP_WAITFOR macros - they can
check the EOF flag every time the coroutine is resumed.)
Secondly, the error reporting itself is changed around again. I'd
expected to put some data fields in the public PacketProtocolLayer
structure that it could set to report errors in the same way as the
BPPs have been doing, but in the end, I decided propagating all those
data fields around was a pain and that even the BPPs shouldn't have
been doing it that way. So I've reverted to a system where everything
calls back to functions in ssh.c itself to report any connection-
ending condition. But there's a new family of those functions,
categorising the possible such conditions by semantics, and each one
has a different set of detailed effects (e.g. how rudely to close the
network connection, what exit status should be passed back to the
whole application, whether to send a disconnect message and/or display
a GUI error box).
I don't expect this to be immediately perfect: of course, the code has
been through a big upheaval, new bugs are expected, and I haven't been
able to do a full job of testing (e.g. I haven't tested every auth or
kex method). But I've checked that it _basically_ works - both SSH
protocols, all the different kinds of forwarding channel, more than
one auth method, Windows and Linux, connection sharing - and I think
it's now at the point where the easiest way to find further bugs is to
let it out into the wild and see what users can spot.
2018-09-24 17:28:16 +00:00
|
|
|
strbuf_free(pkblob);
|
|
|
|
strbuf_free(sigblob);
|
|
|
|
|
|
|
|
pq_push(s->ppl.out_pq, s->pktout);
|
|
|
|
ppl_logevent(("Sent public key signature"));
|
|
|
|
s->type = AUTH_TYPE_PUBLICKEY;
|
|
|
|
ssh_key_free(key->key);
|
|
|
|
sfree(key->comment);
|
|
|
|
sfree(key);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifndef NO_GSSAPI
|
|
|
|
} else if (s->can_gssapi && !s->tried_gssapi) {
|
|
|
|
|
|
|
|
/* gssapi-with-mic authentication */
|
|
|
|
|
|
|
|
ptrlen data;
|
|
|
|
|
|
|
|
s->type = AUTH_TYPE_GSSAPI;
|
|
|
|
s->tried_gssapi = TRUE;
|
|
|
|
s->ppl.bpp->pls->actx = SSH2_PKTCTX_GSSAPI;
|
|
|
|
|
|
|
|
if (s->shgss->lib->gsslogmsg)
|
|
|
|
ppl_logevent(("%s", s->shgss->lib->gsslogmsg));
|
|
|
|
|
|
|
|
/* Sending USERAUTH_REQUEST with "gssapi-with-mic" method */
|
|
|
|
ppl_logevent(("Trying gssapi-with-mic..."));
|
|
|
|
s->pktout = ssh_bpp_new_pktout(
|
|
|
|
s->ppl.bpp, SSH2_MSG_USERAUTH_REQUEST);
|
|
|
|
put_stringz(s->pktout, s->username);
|
2018-10-09 17:11:17 +00:00
|
|
|
put_stringz(s->pktout, s->successor_layer->vt->name);
|
Move most of ssh.c out into separate source files.
I've tried to separate out as many individually coherent changes from
this work as I could into their own commits, but here's where I run
out and have to commit the rest of this major refactoring as a
big-bang change.
Most of ssh.c is now no longer in ssh.c: all five of the main
coroutines that handle layers of the SSH-1 and SSH-2 protocols now
each have their own source file to live in, and a lot of the
supporting functions have moved into the appropriate one of those too.
The new abstraction is a vtable called 'PacketProtocolLayer', which
has an input and output packet queue. Each layer's main coroutine is
invoked from the method ssh_ppl_process_queue(), which is usually
(though not exclusively) triggered automatically when things are
pushed on the input queue. In SSH-2, the base layer is the transport
protocol, and it contains a pair of subsidiary queues by which it
passes some of its packets to the higher SSH-2 layers - first userauth
and then connection, which are peers at the same level, with the
former abdicating in favour of the latter at the appropriate moment.
SSH-1 is simpler: the whole login phase of the protocol (crypto setup
and authentication) is all in one module, and since SSH-1 has no
repeat key exchange, that setup layer abdicates in favour of the
connection phase when it's done.
ssh.c itself is now about a tenth of its old size (which all by itself
is cause for celebration!). Its main job is to set up all the layers,
hook them up to each other and to the BPP, and to funnel data back and
forth between that collection of modules and external things such as
the network and the terminal. Once it's set up a collection of packet
protocol layers, it communicates with them partly by calling methods
of the base layer (and if that's ssh2transport then it will delegate
some functionality to the corresponding methods of its higher layer),
and partly by talking directly to the connection layer no matter where
it is in the stack by means of the separate ConnectionLayer vtable
which I introduced in commit 8001dd4cb, and to which I've now added
quite a few extra methods replacing services that used to be internal
function calls within ssh.c.
(One effect of this is that the SSH-1 and SSH-2 channel storage is now
no longer shared - there are distinct struct types ssh1_channel and
ssh2_channel. That means a bit more code duplication, but on the plus
side, a lot fewer confusing conditionals in the middle of half-shared
functions, and less risk of a piece of SSH-1 escaping into SSH-2 or
vice versa, which I remember has happened at least once in the past.)
The bulk of this commit introduces the five new source files, their
common header sshppl.h and some shared supporting routines in
sshcommon.c, and rewrites nearly all of ssh.c itself. But it also
includes a couple of other changes that I couldn't separate easily
enough:
Firstly, there's a new handling for socket EOF, in which ssh.c sets an
'input_eof' flag in the BPP, and that responds by checking a flag that
tells it whether to report the EOF as an error or not. (This is the
main reason for those new BPP_READ / BPP_WAITFOR macros - they can
check the EOF flag every time the coroutine is resumed.)
Secondly, the error reporting itself is changed around again. I'd
expected to put some data fields in the public PacketProtocolLayer
structure that it could set to report errors in the same way as the
BPPs have been doing, but in the end, I decided propagating all those
data fields around was a pain and that even the BPPs shouldn't have
been doing it that way. So I've reverted to a system where everything
calls back to functions in ssh.c itself to report any connection-
ending condition. But there's a new family of those functions,
categorising the possible such conditions by semantics, and each one
has a different set of detailed effects (e.g. how rudely to close the
network connection, what exit status should be passed back to the
whole application, whether to send a disconnect message and/or display
a GUI error box).
I don't expect this to be immediately perfect: of course, the code has
been through a big upheaval, new bugs are expected, and I haven't been
able to do a full job of testing (e.g. I haven't tested every auth or
kex method). But I've checked that it _basically_ works - both SSH
protocols, all the different kinds of forwarding channel, more than
one auth method, Windows and Linux, connection sharing - and I think
it's now at the point where the easiest way to find further bugs is to
let it out into the wild and see what users can spot.
2018-09-24 17:28:16 +00:00
|
|
|
put_stringz(s->pktout, "gssapi-with-mic");
|
|
|
|
ppl_logevent(("Attempting GSSAPI authentication"));
|
|
|
|
|
|
|
|
/* add mechanism info */
|
|
|
|
s->shgss->lib->indicate_mech(s->shgss->lib, &s->gss_buf);
|
|
|
|
|
|
|
|
/* number of GSSAPI mechanisms */
|
|
|
|
put_uint32(s->pktout, 1);
|
|
|
|
|
|
|
|
/* length of OID + 2 */
|
|
|
|
put_uint32(s->pktout, s->gss_buf.length + 2);
|
|
|
|
put_byte(s->pktout, SSH2_GSS_OIDTYPE);
|
|
|
|
|
|
|
|
/* length of OID */
|
|
|
|
put_byte(s->pktout, s->gss_buf.length);
|
|
|
|
|
|
|
|
put_data(s->pktout, s->gss_buf.value, s->gss_buf.length);
|
|
|
|
pq_push(s->ppl.out_pq, s->pktout);
|
|
|
|
crMaybeWaitUntilV((pktin = ssh2_userauth_pop(s)) != NULL);
|
|
|
|
if (pktin->type != SSH2_MSG_USERAUTH_GSSAPI_RESPONSE) {
|
|
|
|
ppl_logevent(("GSSAPI authentication request refused"));
|
|
|
|
pq_push_front(s->ppl.in_pq, pktin);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* check returned packet ... */
|
|
|
|
|
|
|
|
data = get_string(pktin);
|
|
|
|
s->gss_rcvtok.value = (char *)data.ptr;
|
|
|
|
s->gss_rcvtok.length = data.len;
|
|
|
|
if (s->gss_rcvtok.length != s->gss_buf.length + 2 ||
|
|
|
|
((char *)s->gss_rcvtok.value)[0] != SSH2_GSS_OIDTYPE ||
|
|
|
|
((char *)s->gss_rcvtok.value)[1] != s->gss_buf.length ||
|
|
|
|
memcmp((char *)s->gss_rcvtok.value + 2,
|
|
|
|
s->gss_buf.value,s->gss_buf.length) ) {
|
|
|
|
ppl_logevent(("GSSAPI authentication - wrong response "
|
|
|
|
"from server"));
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Import server name if not cached from KEX */
|
|
|
|
if (s->shgss->srv_name == GSS_C_NO_NAME) {
|
|
|
|
s->gss_stat = s->shgss->lib->import_name(
|
|
|
|
s->shgss->lib, s->fullhostname, &s->shgss->srv_name);
|
|
|
|
if (s->gss_stat != SSH_GSS_OK) {
|
|
|
|
if (s->gss_stat == SSH_GSS_BAD_HOST_NAME)
|
|
|
|
ppl_logevent(("GSSAPI import name failed -"
|
|
|
|
" Bad service name"));
|
|
|
|
else
|
|
|
|
ppl_logevent(("GSSAPI import name failed"));
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Allocate our gss_ctx */
|
|
|
|
s->gss_stat = s->shgss->lib->acquire_cred(
|
|
|
|
s->shgss->lib, &s->shgss->ctx, NULL);
|
|
|
|
if (s->gss_stat != SSH_GSS_OK) {
|
|
|
|
ppl_logevent(("GSSAPI authentication failed to get "
|
|
|
|
"credentials"));
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* initial tokens are empty */
|
|
|
|
SSH_GSS_CLEAR_BUF(&s->gss_rcvtok);
|
|
|
|
SSH_GSS_CLEAR_BUF(&s->gss_sndtok);
|
|
|
|
|
|
|
|
/* now enter the loop */
|
|
|
|
do {
|
|
|
|
/*
|
|
|
|
* When acquire_cred yields no useful expiration, go with
|
|
|
|
* the service ticket expiration.
|
|
|
|
*/
|
|
|
|
s->gss_stat = s->shgss->lib->init_sec_context
|
|
|
|
(s->shgss->lib,
|
|
|
|
&s->shgss->ctx,
|
|
|
|
s->shgss->srv_name,
|
|
|
|
s->gssapi_fwd,
|
|
|
|
&s->gss_rcvtok,
|
|
|
|
&s->gss_sndtok,
|
|
|
|
NULL,
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
if (s->gss_stat!=SSH_GSS_S_COMPLETE &&
|
|
|
|
s->gss_stat!=SSH_GSS_S_CONTINUE_NEEDED) {
|
|
|
|
ppl_logevent(("GSSAPI authentication initialisation "
|
|
|
|
"failed"));
|
|
|
|
|
|
|
|
if (s->shgss->lib->display_status(s->shgss->lib,
|
|
|
|
s->shgss->ctx, &s->gss_buf) == SSH_GSS_OK) {
|
|
|
|
ppl_logevent(("%s", (char *)s->gss_buf.value));
|
|
|
|
sfree(s->gss_buf.value);
|
|
|
|
}
|
|
|
|
|
|
|
|
pq_push_front(s->ppl.in_pq, pktin);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
ppl_logevent(("GSSAPI authentication initialised"));
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Client and server now exchange tokens until GSSAPI
|
|
|
|
* no longer says CONTINUE_NEEDED
|
|
|
|
*/
|
|
|
|
if (s->gss_sndtok.length != 0) {
|
|
|
|
s->pktout =
|
|
|
|
ssh_bpp_new_pktout(
|
|
|
|
s->ppl.bpp, SSH2_MSG_USERAUTH_GSSAPI_TOKEN);
|
|
|
|
put_string(s->pktout,
|
|
|
|
s->gss_sndtok.value, s->gss_sndtok.length);
|
|
|
|
pq_push(s->ppl.out_pq, s->pktout);
|
|
|
|
s->shgss->lib->free_tok(s->shgss->lib, &s->gss_sndtok);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (s->gss_stat == SSH_GSS_S_CONTINUE_NEEDED) {
|
|
|
|
crMaybeWaitUntilV((pktin = ssh2_userauth_pop(s)) != NULL);
|
|
|
|
if (pktin->type != SSH2_MSG_USERAUTH_GSSAPI_TOKEN) {
|
|
|
|
ppl_logevent(("GSSAPI authentication -"
|
|
|
|
" bad server response"));
|
|
|
|
s->gss_stat = SSH_GSS_FAILURE;
|
|
|
|
pq_push_front(s->ppl.in_pq, pktin);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
data = get_string(pktin);
|
|
|
|
s->gss_rcvtok.value = (char *)data.ptr;
|
|
|
|
s->gss_rcvtok.length = data.len;
|
|
|
|
}
|
|
|
|
} while (s-> gss_stat == SSH_GSS_S_CONTINUE_NEEDED);
|
|
|
|
|
|
|
|
if (s->gss_stat != SSH_GSS_OK) {
|
|
|
|
s->shgss->lib->release_cred(s->shgss->lib, &s->shgss->ctx);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
ppl_logevent(("GSSAPI authentication loop finished OK"));
|
|
|
|
|
|
|
|
/* Now send the MIC */
|
|
|
|
|
|
|
|
s->pktout = ssh2_userauth_gss_packet(s, "gssapi-with-mic");
|
|
|
|
pq_push(s->ppl.out_pq, s->pktout);
|
|
|
|
|
|
|
|
s->shgss->lib->release_cred(s->shgss->lib, &s->shgss->ctx);
|
|
|
|
continue;
|
|
|
|
#endif
|
|
|
|
} else if (s->can_keyb_inter && !s->kbd_inter_refused) {
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Keyboard-interactive authentication.
|
|
|
|
*/
|
|
|
|
|
|
|
|
s->type = AUTH_TYPE_KEYBOARD_INTERACTIVE;
|
|
|
|
|
|
|
|
s->ppl.bpp->pls->actx = SSH2_PKTCTX_KBDINTER;
|
|
|
|
|
|
|
|
s->pktout = ssh_bpp_new_pktout(
|
|
|
|
s->ppl.bpp, SSH2_MSG_USERAUTH_REQUEST);
|
|
|
|
put_stringz(s->pktout, s->username);
|
2018-10-09 17:11:17 +00:00
|
|
|
put_stringz(s->pktout, s->successor_layer->vt->name);
|
Move most of ssh.c out into separate source files.
I've tried to separate out as many individually coherent changes from
this work as I could into their own commits, but here's where I run
out and have to commit the rest of this major refactoring as a
big-bang change.
Most of ssh.c is now no longer in ssh.c: all five of the main
coroutines that handle layers of the SSH-1 and SSH-2 protocols now
each have their own source file to live in, and a lot of the
supporting functions have moved into the appropriate one of those too.
The new abstraction is a vtable called 'PacketProtocolLayer', which
has an input and output packet queue. Each layer's main coroutine is
invoked from the method ssh_ppl_process_queue(), which is usually
(though not exclusively) triggered automatically when things are
pushed on the input queue. In SSH-2, the base layer is the transport
protocol, and it contains a pair of subsidiary queues by which it
passes some of its packets to the higher SSH-2 layers - first userauth
and then connection, which are peers at the same level, with the
former abdicating in favour of the latter at the appropriate moment.
SSH-1 is simpler: the whole login phase of the protocol (crypto setup
and authentication) is all in one module, and since SSH-1 has no
repeat key exchange, that setup layer abdicates in favour of the
connection phase when it's done.
ssh.c itself is now about a tenth of its old size (which all by itself
is cause for celebration!). Its main job is to set up all the layers,
hook them up to each other and to the BPP, and to funnel data back and
forth between that collection of modules and external things such as
the network and the terminal. Once it's set up a collection of packet
protocol layers, it communicates with them partly by calling methods
of the base layer (and if that's ssh2transport then it will delegate
some functionality to the corresponding methods of its higher layer),
and partly by talking directly to the connection layer no matter where
it is in the stack by means of the separate ConnectionLayer vtable
which I introduced in commit 8001dd4cb, and to which I've now added
quite a few extra methods replacing services that used to be internal
function calls within ssh.c.
(One effect of this is that the SSH-1 and SSH-2 channel storage is now
no longer shared - there are distinct struct types ssh1_channel and
ssh2_channel. That means a bit more code duplication, but on the plus
side, a lot fewer confusing conditionals in the middle of half-shared
functions, and less risk of a piece of SSH-1 escaping into SSH-2 or
vice versa, which I remember has happened at least once in the past.)
The bulk of this commit introduces the five new source files, their
common header sshppl.h and some shared supporting routines in
sshcommon.c, and rewrites nearly all of ssh.c itself. But it also
includes a couple of other changes that I couldn't separate easily
enough:
Firstly, there's a new handling for socket EOF, in which ssh.c sets an
'input_eof' flag in the BPP, and that responds by checking a flag that
tells it whether to report the EOF as an error or not. (This is the
main reason for those new BPP_READ / BPP_WAITFOR macros - they can
check the EOF flag every time the coroutine is resumed.)
Secondly, the error reporting itself is changed around again. I'd
expected to put some data fields in the public PacketProtocolLayer
structure that it could set to report errors in the same way as the
BPPs have been doing, but in the end, I decided propagating all those
data fields around was a pain and that even the BPPs shouldn't have
been doing it that way. So I've reverted to a system where everything
calls back to functions in ssh.c itself to report any connection-
ending condition. But there's a new family of those functions,
categorising the possible such conditions by semantics, and each one
has a different set of detailed effects (e.g. how rudely to close the
network connection, what exit status should be passed back to the
whole application, whether to send a disconnect message and/or display
a GUI error box).
I don't expect this to be immediately perfect: of course, the code has
been through a big upheaval, new bugs are expected, and I haven't been
able to do a full job of testing (e.g. I haven't tested every auth or
kex method). But I've checked that it _basically_ works - both SSH
protocols, all the different kinds of forwarding channel, more than
one auth method, Windows and Linux, connection sharing - and I think
it's now at the point where the easiest way to find further bugs is to
let it out into the wild and see what users can spot.
2018-09-24 17:28:16 +00:00
|
|
|
put_stringz(s->pktout, "keyboard-interactive");
|
|
|
|
/* method */
|
|
|
|
put_stringz(s->pktout, ""); /* lang */
|
|
|
|
put_stringz(s->pktout, ""); /* submethods */
|
|
|
|
pq_push(s->ppl.out_pq, s->pktout);
|
|
|
|
|
|
|
|
ppl_logevent(("Attempting keyboard-interactive authentication"));
|
|
|
|
|
|
|
|
crMaybeWaitUntilV((pktin = ssh2_userauth_pop(s)) != NULL);
|
|
|
|
if (pktin->type != SSH2_MSG_USERAUTH_INFO_REQUEST) {
|
|
|
|
/* Server is not willing to do keyboard-interactive
|
|
|
|
* at all (or, bizarrely but legally, accepts the
|
|
|
|
* user without actually issuing any prompts).
|
|
|
|
* Give up on it entirely. */
|
|
|
|
pq_push_front(s->ppl.in_pq, pktin);
|
|
|
|
s->type = AUTH_TYPE_KEYBOARD_INTERACTIVE_QUIET;
|
|
|
|
s->kbd_inter_refused = TRUE; /* don't try it again */
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Loop while the server continues to send INFO_REQUESTs.
|
|
|
|
*/
|
|
|
|
while (pktin->type == SSH2_MSG_USERAUTH_INFO_REQUEST) {
|
|
|
|
|
|
|
|
ptrlen name, inst;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We've got a fresh USERAUTH_INFO_REQUEST.
|
|
|
|
* Get the preamble and start building a prompt.
|
|
|
|
*/
|
|
|
|
name = get_string(pktin);
|
|
|
|
inst = get_string(pktin);
|
|
|
|
get_string(pktin); /* skip language tag */
|
New abstraction 'Seat', to pass to backends.
This is a new vtable-based abstraction which is passed to a backend in
place of Frontend, and it implements only the subset of the Frontend
functions needed by a backend. (Many other Frontend functions still
exist, notably the wide range of things called by terminal.c providing
platform-independent operations on the GUI terminal window.)
The purpose of making it a vtable is that this opens up the
possibility of creating a backend as an internal implementation detail
of some other activity, by providing just that one backend with a
custom Seat that implements the methods differently.
For example, this refactoring should make it feasible to directly
implement an SSH proxy type, aka the 'jump host' feature supported by
OpenSSH, aka 'open a secondary SSH session in MAINCHAN_DIRECT_TCP
mode, and then expose the main channel of that as the Socket for the
primary connection'. (Which of course you can already do by spawning
'plink -nc' as a separate proxy process, but this would permit it in
the _same_ process without anything getting confused.)
I've centralised a full set of stub methods in misc.c for the new
abstraction, which allows me to get rid of several annoying stubs in
the previous code. Also, while I'm here, I've moved a lot of
duplicated modalfatalbox() type functions from application main
program files into wincons.c / uxcons.c, which I think saves
duplication overall. (A minor visible effect is that the prefixes on
those console-based fatal error messages will now be more consistent
between applications.)
2018-10-11 18:58:42 +00:00
|
|
|
s->cur_prompt = new_prompts();
|
Move most of ssh.c out into separate source files.
I've tried to separate out as many individually coherent changes from
this work as I could into their own commits, but here's where I run
out and have to commit the rest of this major refactoring as a
big-bang change.
Most of ssh.c is now no longer in ssh.c: all five of the main
coroutines that handle layers of the SSH-1 and SSH-2 protocols now
each have their own source file to live in, and a lot of the
supporting functions have moved into the appropriate one of those too.
The new abstraction is a vtable called 'PacketProtocolLayer', which
has an input and output packet queue. Each layer's main coroutine is
invoked from the method ssh_ppl_process_queue(), which is usually
(though not exclusively) triggered automatically when things are
pushed on the input queue. In SSH-2, the base layer is the transport
protocol, and it contains a pair of subsidiary queues by which it
passes some of its packets to the higher SSH-2 layers - first userauth
and then connection, which are peers at the same level, with the
former abdicating in favour of the latter at the appropriate moment.
SSH-1 is simpler: the whole login phase of the protocol (crypto setup
and authentication) is all in one module, and since SSH-1 has no
repeat key exchange, that setup layer abdicates in favour of the
connection phase when it's done.
ssh.c itself is now about a tenth of its old size (which all by itself
is cause for celebration!). Its main job is to set up all the layers,
hook them up to each other and to the BPP, and to funnel data back and
forth between that collection of modules and external things such as
the network and the terminal. Once it's set up a collection of packet
protocol layers, it communicates with them partly by calling methods
of the base layer (and if that's ssh2transport then it will delegate
some functionality to the corresponding methods of its higher layer),
and partly by talking directly to the connection layer no matter where
it is in the stack by means of the separate ConnectionLayer vtable
which I introduced in commit 8001dd4cb, and to which I've now added
quite a few extra methods replacing services that used to be internal
function calls within ssh.c.
(One effect of this is that the SSH-1 and SSH-2 channel storage is now
no longer shared - there are distinct struct types ssh1_channel and
ssh2_channel. That means a bit more code duplication, but on the plus
side, a lot fewer confusing conditionals in the middle of half-shared
functions, and less risk of a piece of SSH-1 escaping into SSH-2 or
vice versa, which I remember has happened at least once in the past.)
The bulk of this commit introduces the five new source files, their
common header sshppl.h and some shared supporting routines in
sshcommon.c, and rewrites nearly all of ssh.c itself. But it also
includes a couple of other changes that I couldn't separate easily
enough:
Firstly, there's a new handling for socket EOF, in which ssh.c sets an
'input_eof' flag in the BPP, and that responds by checking a flag that
tells it whether to report the EOF as an error or not. (This is the
main reason for those new BPP_READ / BPP_WAITFOR macros - they can
check the EOF flag every time the coroutine is resumed.)
Secondly, the error reporting itself is changed around again. I'd
expected to put some data fields in the public PacketProtocolLayer
structure that it could set to report errors in the same way as the
BPPs have been doing, but in the end, I decided propagating all those
data fields around was a pain and that even the BPPs shouldn't have
been doing it that way. So I've reverted to a system where everything
calls back to functions in ssh.c itself to report any connection-
ending condition. But there's a new family of those functions,
categorising the possible such conditions by semantics, and each one
has a different set of detailed effects (e.g. how rudely to close the
network connection, what exit status should be passed back to the
whole application, whether to send a disconnect message and/or display
a GUI error box).
I don't expect this to be immediately perfect: of course, the code has
been through a big upheaval, new bugs are expected, and I haven't been
able to do a full job of testing (e.g. I haven't tested every auth or
kex method). But I've checked that it _basically_ works - both SSH
protocols, all the different kinds of forwarding channel, more than
one auth method, Windows and Linux, connection sharing - and I think
it's now at the point where the easiest way to find further bugs is to
let it out into the wild and see what users can spot.
2018-09-24 17:28:16 +00:00
|
|
|
s->cur_prompt->to_server = TRUE;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Get any prompt(s) from the packet.
|
|
|
|
*/
|
|
|
|
s->num_prompts = get_uint32(pktin);
|
|
|
|
for (i = 0; i < s->num_prompts; i++) {
|
|
|
|
ptrlen prompt;
|
|
|
|
int echo;
|
|
|
|
static char noprompt[] =
|
|
|
|
"<server failed to send prompt>: ";
|
|
|
|
|
|
|
|
prompt = get_string(pktin);
|
|
|
|
echo = get_bool(pktin);
|
|
|
|
if (!prompt.len) {
|
|
|
|
prompt.ptr = noprompt;
|
|
|
|
prompt.len = lenof(noprompt)-1;
|
|
|
|
}
|
|
|
|
add_prompt(s->cur_prompt, mkstr(prompt), echo);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (name.len) {
|
|
|
|
/* FIXME: better prefix to distinguish from
|
|
|
|
* local prompts? */
|
|
|
|
s->cur_prompt->name =
|
|
|
|
dupprintf("SSH server: %.*s", PTRLEN_PRINTF(name));
|
|
|
|
s->cur_prompt->name_reqd = TRUE;
|
|
|
|
} else {
|
|
|
|
s->cur_prompt->name =
|
|
|
|
dupstr("SSH server authentication");
|
|
|
|
s->cur_prompt->name_reqd = FALSE;
|
|
|
|
}
|
|
|
|
/* We add a prefix to try to make it clear that a prompt
|
|
|
|
* has come from the server.
|
|
|
|
* FIXME: ugly to print "Using..." in prompt _every_
|
|
|
|
* time round. Can this be done more subtly? */
|
|
|
|
/* Special case: for reasons best known to themselves,
|
|
|
|
* some servers send k-i requests with no prompts and
|
|
|
|
* nothing to display. Keep quiet in this case. */
|
|
|
|
if (s->num_prompts || name.len || inst.len) {
|
|
|
|
s->cur_prompt->instruction =
|
|
|
|
dupprintf("Using keyboard-interactive "
|
|
|
|
"authentication.%s%.*s",
|
|
|
|
inst.len ? "\n" : "",
|
|
|
|
PTRLEN_PRINTF(inst));
|
|
|
|
s->cur_prompt->instr_reqd = TRUE;
|
|
|
|
} else {
|
|
|
|
s->cur_prompt->instr_reqd = FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Display any instructions, and get the user's
|
|
|
|
* response(s).
|
|
|
|
*/
|
New abstraction 'Seat', to pass to backends.
This is a new vtable-based abstraction which is passed to a backend in
place of Frontend, and it implements only the subset of the Frontend
functions needed by a backend. (Many other Frontend functions still
exist, notably the wide range of things called by terminal.c providing
platform-independent operations on the GUI terminal window.)
The purpose of making it a vtable is that this opens up the
possibility of creating a backend as an internal implementation detail
of some other activity, by providing just that one backend with a
custom Seat that implements the methods differently.
For example, this refactoring should make it feasible to directly
implement an SSH proxy type, aka the 'jump host' feature supported by
OpenSSH, aka 'open a secondary SSH session in MAINCHAN_DIRECT_TCP
mode, and then expose the main channel of that as the Socket for the
primary connection'. (Which of course you can already do by spawning
'plink -nc' as a separate proxy process, but this would permit it in
the _same_ process without anything getting confused.)
I've centralised a full set of stub methods in misc.c for the new
abstraction, which allows me to get rid of several annoying stubs in
the previous code. Also, while I'm here, I've moved a lot of
duplicated modalfatalbox() type functions from application main
program files into wincons.c / uxcons.c, which I think saves
duplication overall. (A minor visible effect is that the prefixes on
those console-based fatal error messages will now be more consistent
between applications.)
2018-10-11 18:58:42 +00:00
|
|
|
s->userpass_ret = seat_get_userpass_input(
|
|
|
|
s->ppl.seat, s->cur_prompt, NULL);
|
Move most of ssh.c out into separate source files.
I've tried to separate out as many individually coherent changes from
this work as I could into their own commits, but here's where I run
out and have to commit the rest of this major refactoring as a
big-bang change.
Most of ssh.c is now no longer in ssh.c: all five of the main
coroutines that handle layers of the SSH-1 and SSH-2 protocols now
each have their own source file to live in, and a lot of the
supporting functions have moved into the appropriate one of those too.
The new abstraction is a vtable called 'PacketProtocolLayer', which
has an input and output packet queue. Each layer's main coroutine is
invoked from the method ssh_ppl_process_queue(), which is usually
(though not exclusively) triggered automatically when things are
pushed on the input queue. In SSH-2, the base layer is the transport
protocol, and it contains a pair of subsidiary queues by which it
passes some of its packets to the higher SSH-2 layers - first userauth
and then connection, which are peers at the same level, with the
former abdicating in favour of the latter at the appropriate moment.
SSH-1 is simpler: the whole login phase of the protocol (crypto setup
and authentication) is all in one module, and since SSH-1 has no
repeat key exchange, that setup layer abdicates in favour of the
connection phase when it's done.
ssh.c itself is now about a tenth of its old size (which all by itself
is cause for celebration!). Its main job is to set up all the layers,
hook them up to each other and to the BPP, and to funnel data back and
forth between that collection of modules and external things such as
the network and the terminal. Once it's set up a collection of packet
protocol layers, it communicates with them partly by calling methods
of the base layer (and if that's ssh2transport then it will delegate
some functionality to the corresponding methods of its higher layer),
and partly by talking directly to the connection layer no matter where
it is in the stack by means of the separate ConnectionLayer vtable
which I introduced in commit 8001dd4cb, and to which I've now added
quite a few extra methods replacing services that used to be internal
function calls within ssh.c.
(One effect of this is that the SSH-1 and SSH-2 channel storage is now
no longer shared - there are distinct struct types ssh1_channel and
ssh2_channel. That means a bit more code duplication, but on the plus
side, a lot fewer confusing conditionals in the middle of half-shared
functions, and less risk of a piece of SSH-1 escaping into SSH-2 or
vice versa, which I remember has happened at least once in the past.)
The bulk of this commit introduces the five new source files, their
common header sshppl.h and some shared supporting routines in
sshcommon.c, and rewrites nearly all of ssh.c itself. But it also
includes a couple of other changes that I couldn't separate easily
enough:
Firstly, there's a new handling for socket EOF, in which ssh.c sets an
'input_eof' flag in the BPP, and that responds by checking a flag that
tells it whether to report the EOF as an error or not. (This is the
main reason for those new BPP_READ / BPP_WAITFOR macros - they can
check the EOF flag every time the coroutine is resumed.)
Secondly, the error reporting itself is changed around again. I'd
expected to put some data fields in the public PacketProtocolLayer
structure that it could set to report errors in the same way as the
BPPs have been doing, but in the end, I decided propagating all those
data fields around was a pain and that even the BPPs shouldn't have
been doing it that way. So I've reverted to a system where everything
calls back to functions in ssh.c itself to report any connection-
ending condition. But there's a new family of those functions,
categorising the possible such conditions by semantics, and each one
has a different set of detailed effects (e.g. how rudely to close the
network connection, what exit status should be passed back to the
whole application, whether to send a disconnect message and/or display
a GUI error box).
I don't expect this to be immediately perfect: of course, the code has
been through a big upheaval, new bugs are expected, and I haven't been
able to do a full job of testing (e.g. I haven't tested every auth or
kex method). But I've checked that it _basically_ works - both SSH
protocols, all the different kinds of forwarding channel, more than
one auth method, Windows and Linux, connection sharing - and I think
it's now at the point where the easiest way to find further bugs is to
let it out into the wild and see what users can spot.
2018-09-24 17:28:16 +00:00
|
|
|
while (1) {
|
|
|
|
while (s->userpass_ret < 0 &&
|
|
|
|
bufchain_size(s->ppl.user_input) > 0)
|
New abstraction 'Seat', to pass to backends.
This is a new vtable-based abstraction which is passed to a backend in
place of Frontend, and it implements only the subset of the Frontend
functions needed by a backend. (Many other Frontend functions still
exist, notably the wide range of things called by terminal.c providing
platform-independent operations on the GUI terminal window.)
The purpose of making it a vtable is that this opens up the
possibility of creating a backend as an internal implementation detail
of some other activity, by providing just that one backend with a
custom Seat that implements the methods differently.
For example, this refactoring should make it feasible to directly
implement an SSH proxy type, aka the 'jump host' feature supported by
OpenSSH, aka 'open a secondary SSH session in MAINCHAN_DIRECT_TCP
mode, and then expose the main channel of that as the Socket for the
primary connection'. (Which of course you can already do by spawning
'plink -nc' as a separate proxy process, but this would permit it in
the _same_ process without anything getting confused.)
I've centralised a full set of stub methods in misc.c for the new
abstraction, which allows me to get rid of several annoying stubs in
the previous code. Also, while I'm here, I've moved a lot of
duplicated modalfatalbox() type functions from application main
program files into wincons.c / uxcons.c, which I think saves
duplication overall. (A minor visible effect is that the prefixes on
those console-based fatal error messages will now be more consistent
between applications.)
2018-10-11 18:58:42 +00:00
|
|
|
s->userpass_ret = seat_get_userpass_input(
|
|
|
|
s->ppl.seat, s->cur_prompt, s->ppl.user_input);
|
Move most of ssh.c out into separate source files.
I've tried to separate out as many individually coherent changes from
this work as I could into their own commits, but here's where I run
out and have to commit the rest of this major refactoring as a
big-bang change.
Most of ssh.c is now no longer in ssh.c: all five of the main
coroutines that handle layers of the SSH-1 and SSH-2 protocols now
each have their own source file to live in, and a lot of the
supporting functions have moved into the appropriate one of those too.
The new abstraction is a vtable called 'PacketProtocolLayer', which
has an input and output packet queue. Each layer's main coroutine is
invoked from the method ssh_ppl_process_queue(), which is usually
(though not exclusively) triggered automatically when things are
pushed on the input queue. In SSH-2, the base layer is the transport
protocol, and it contains a pair of subsidiary queues by which it
passes some of its packets to the higher SSH-2 layers - first userauth
and then connection, which are peers at the same level, with the
former abdicating in favour of the latter at the appropriate moment.
SSH-1 is simpler: the whole login phase of the protocol (crypto setup
and authentication) is all in one module, and since SSH-1 has no
repeat key exchange, that setup layer abdicates in favour of the
connection phase when it's done.
ssh.c itself is now about a tenth of its old size (which all by itself
is cause for celebration!). Its main job is to set up all the layers,
hook them up to each other and to the BPP, and to funnel data back and
forth between that collection of modules and external things such as
the network and the terminal. Once it's set up a collection of packet
protocol layers, it communicates with them partly by calling methods
of the base layer (and if that's ssh2transport then it will delegate
some functionality to the corresponding methods of its higher layer),
and partly by talking directly to the connection layer no matter where
it is in the stack by means of the separate ConnectionLayer vtable
which I introduced in commit 8001dd4cb, and to which I've now added
quite a few extra methods replacing services that used to be internal
function calls within ssh.c.
(One effect of this is that the SSH-1 and SSH-2 channel storage is now
no longer shared - there are distinct struct types ssh1_channel and
ssh2_channel. That means a bit more code duplication, but on the plus
side, a lot fewer confusing conditionals in the middle of half-shared
functions, and less risk of a piece of SSH-1 escaping into SSH-2 or
vice versa, which I remember has happened at least once in the past.)
The bulk of this commit introduces the five new source files, their
common header sshppl.h and some shared supporting routines in
sshcommon.c, and rewrites nearly all of ssh.c itself. But it also
includes a couple of other changes that I couldn't separate easily
enough:
Firstly, there's a new handling for socket EOF, in which ssh.c sets an
'input_eof' flag in the BPP, and that responds by checking a flag that
tells it whether to report the EOF as an error or not. (This is the
main reason for those new BPP_READ / BPP_WAITFOR macros - they can
check the EOF flag every time the coroutine is resumed.)
Secondly, the error reporting itself is changed around again. I'd
expected to put some data fields in the public PacketProtocolLayer
structure that it could set to report errors in the same way as the
BPPs have been doing, but in the end, I decided propagating all those
data fields around was a pain and that even the BPPs shouldn't have
been doing it that way. So I've reverted to a system where everything
calls back to functions in ssh.c itself to report any connection-
ending condition. But there's a new family of those functions,
categorising the possible such conditions by semantics, and each one
has a different set of detailed effects (e.g. how rudely to close the
network connection, what exit status should be passed back to the
whole application, whether to send a disconnect message and/or display
a GUI error box).
I don't expect this to be immediately perfect: of course, the code has
been through a big upheaval, new bugs are expected, and I haven't been
able to do a full job of testing (e.g. I haven't tested every auth or
kex method). But I've checked that it _basically_ works - both SSH
protocols, all the different kinds of forwarding channel, more than
one auth method, Windows and Linux, connection sharing - and I think
it's now at the point where the easiest way to find further bugs is to
let it out into the wild and see what users can spot.
2018-09-24 17:28:16 +00:00
|
|
|
|
|
|
|
if (s->userpass_ret >= 0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
s->want_user_input = TRUE;
|
|
|
|
crReturnV;
|
|
|
|
s->want_user_input = FALSE;
|
|
|
|
}
|
|
|
|
if (!s->userpass_ret) {
|
|
|
|
/*
|
|
|
|
* Failed to get responses. Terminate.
|
|
|
|
*/
|
|
|
|
free_prompts(s->cur_prompt);
|
|
|
|
ssh_bpp_queue_disconnect(
|
|
|
|
s->ppl.bpp, "Unable to authenticate",
|
|
|
|
SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER);
|
|
|
|
ssh_user_close(s->ppl.ssh, "User aborted during "
|
|
|
|
"keyboard-interactive authentication");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Send the response(s) to the server.
|
|
|
|
*/
|
|
|
|
s->pktout = ssh_bpp_new_pktout(
|
|
|
|
s->ppl.bpp, SSH2_MSG_USERAUTH_INFO_RESPONSE);
|
|
|
|
put_uint32(s->pktout, s->num_prompts);
|
|
|
|
for (i=0; i < s->num_prompts; i++) {
|
|
|
|
put_stringz(s->pktout,
|
|
|
|
s->cur_prompt->prompts[i]->result);
|
|
|
|
}
|
|
|
|
s->pktout->minlen = 256;
|
|
|
|
pq_push(s->ppl.out_pq, s->pktout);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Free the prompts structure from this iteration.
|
|
|
|
* If there's another, a new one will be allocated
|
|
|
|
* when we return to the top of this while loop.
|
|
|
|
*/
|
|
|
|
free_prompts(s->cur_prompt);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Get the next packet in case it's another
|
|
|
|
* INFO_REQUEST.
|
|
|
|
*/
|
|
|
|
crMaybeWaitUntilV((pktin = ssh2_userauth_pop(s)) != NULL);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We should have SUCCESS or FAILURE now.
|
|
|
|
*/
|
|
|
|
pq_push_front(s->ppl.in_pq, pktin);
|
|
|
|
|
|
|
|
} else if (s->can_passwd) {
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Plain old password authentication.
|
|
|
|
*/
|
|
|
|
int changereq_first_time; /* not live over crReturn */
|
|
|
|
|
|
|
|
s->ppl.bpp->pls->actx = SSH2_PKTCTX_PASSWORD;
|
|
|
|
|
New abstraction 'Seat', to pass to backends.
This is a new vtable-based abstraction which is passed to a backend in
place of Frontend, and it implements only the subset of the Frontend
functions needed by a backend. (Many other Frontend functions still
exist, notably the wide range of things called by terminal.c providing
platform-independent operations on the GUI terminal window.)
The purpose of making it a vtable is that this opens up the
possibility of creating a backend as an internal implementation detail
of some other activity, by providing just that one backend with a
custom Seat that implements the methods differently.
For example, this refactoring should make it feasible to directly
implement an SSH proxy type, aka the 'jump host' feature supported by
OpenSSH, aka 'open a secondary SSH session in MAINCHAN_DIRECT_TCP
mode, and then expose the main channel of that as the Socket for the
primary connection'. (Which of course you can already do by spawning
'plink -nc' as a separate proxy process, but this would permit it in
the _same_ process without anything getting confused.)
I've centralised a full set of stub methods in misc.c for the new
abstraction, which allows me to get rid of several annoying stubs in
the previous code. Also, while I'm here, I've moved a lot of
duplicated modalfatalbox() type functions from application main
program files into wincons.c / uxcons.c, which I think saves
duplication overall. (A minor visible effect is that the prefixes on
those console-based fatal error messages will now be more consistent
between applications.)
2018-10-11 18:58:42 +00:00
|
|
|
s->cur_prompt = new_prompts();
|
Move most of ssh.c out into separate source files.
I've tried to separate out as many individually coherent changes from
this work as I could into their own commits, but here's where I run
out and have to commit the rest of this major refactoring as a
big-bang change.
Most of ssh.c is now no longer in ssh.c: all five of the main
coroutines that handle layers of the SSH-1 and SSH-2 protocols now
each have their own source file to live in, and a lot of the
supporting functions have moved into the appropriate one of those too.
The new abstraction is a vtable called 'PacketProtocolLayer', which
has an input and output packet queue. Each layer's main coroutine is
invoked from the method ssh_ppl_process_queue(), which is usually
(though not exclusively) triggered automatically when things are
pushed on the input queue. In SSH-2, the base layer is the transport
protocol, and it contains a pair of subsidiary queues by which it
passes some of its packets to the higher SSH-2 layers - first userauth
and then connection, which are peers at the same level, with the
former abdicating in favour of the latter at the appropriate moment.
SSH-1 is simpler: the whole login phase of the protocol (crypto setup
and authentication) is all in one module, and since SSH-1 has no
repeat key exchange, that setup layer abdicates in favour of the
connection phase when it's done.
ssh.c itself is now about a tenth of its old size (which all by itself
is cause for celebration!). Its main job is to set up all the layers,
hook them up to each other and to the BPP, and to funnel data back and
forth between that collection of modules and external things such as
the network and the terminal. Once it's set up a collection of packet
protocol layers, it communicates with them partly by calling methods
of the base layer (and if that's ssh2transport then it will delegate
some functionality to the corresponding methods of its higher layer),
and partly by talking directly to the connection layer no matter where
it is in the stack by means of the separate ConnectionLayer vtable
which I introduced in commit 8001dd4cb, and to which I've now added
quite a few extra methods replacing services that used to be internal
function calls within ssh.c.
(One effect of this is that the SSH-1 and SSH-2 channel storage is now
no longer shared - there are distinct struct types ssh1_channel and
ssh2_channel. That means a bit more code duplication, but on the plus
side, a lot fewer confusing conditionals in the middle of half-shared
functions, and less risk of a piece of SSH-1 escaping into SSH-2 or
vice versa, which I remember has happened at least once in the past.)
The bulk of this commit introduces the five new source files, their
common header sshppl.h and some shared supporting routines in
sshcommon.c, and rewrites nearly all of ssh.c itself. But it also
includes a couple of other changes that I couldn't separate easily
enough:
Firstly, there's a new handling for socket EOF, in which ssh.c sets an
'input_eof' flag in the BPP, and that responds by checking a flag that
tells it whether to report the EOF as an error or not. (This is the
main reason for those new BPP_READ / BPP_WAITFOR macros - they can
check the EOF flag every time the coroutine is resumed.)
Secondly, the error reporting itself is changed around again. I'd
expected to put some data fields in the public PacketProtocolLayer
structure that it could set to report errors in the same way as the
BPPs have been doing, but in the end, I decided propagating all those
data fields around was a pain and that even the BPPs shouldn't have
been doing it that way. So I've reverted to a system where everything
calls back to functions in ssh.c itself to report any connection-
ending condition. But there's a new family of those functions,
categorising the possible such conditions by semantics, and each one
has a different set of detailed effects (e.g. how rudely to close the
network connection, what exit status should be passed back to the
whole application, whether to send a disconnect message and/or display
a GUI error box).
I don't expect this to be immediately perfect: of course, the code has
been through a big upheaval, new bugs are expected, and I haven't been
able to do a full job of testing (e.g. I haven't tested every auth or
kex method). But I've checked that it _basically_ works - both SSH
protocols, all the different kinds of forwarding channel, more than
one auth method, Windows and Linux, connection sharing - and I think
it's now at the point where the easiest way to find further bugs is to
let it out into the wild and see what users can spot.
2018-09-24 17:28:16 +00:00
|
|
|
s->cur_prompt->to_server = TRUE;
|
|
|
|
s->cur_prompt->name = dupstr("SSH password");
|
|
|
|
add_prompt(s->cur_prompt, dupprintf("%s@%s's password: ",
|
|
|
|
s->username, s->hostname),
|
|
|
|
FALSE);
|
|
|
|
|
New abstraction 'Seat', to pass to backends.
This is a new vtable-based abstraction which is passed to a backend in
place of Frontend, and it implements only the subset of the Frontend
functions needed by a backend. (Many other Frontend functions still
exist, notably the wide range of things called by terminal.c providing
platform-independent operations on the GUI terminal window.)
The purpose of making it a vtable is that this opens up the
possibility of creating a backend as an internal implementation detail
of some other activity, by providing just that one backend with a
custom Seat that implements the methods differently.
For example, this refactoring should make it feasible to directly
implement an SSH proxy type, aka the 'jump host' feature supported by
OpenSSH, aka 'open a secondary SSH session in MAINCHAN_DIRECT_TCP
mode, and then expose the main channel of that as the Socket for the
primary connection'. (Which of course you can already do by spawning
'plink -nc' as a separate proxy process, but this would permit it in
the _same_ process without anything getting confused.)
I've centralised a full set of stub methods in misc.c for the new
abstraction, which allows me to get rid of several annoying stubs in
the previous code. Also, while I'm here, I've moved a lot of
duplicated modalfatalbox() type functions from application main
program files into wincons.c / uxcons.c, which I think saves
duplication overall. (A minor visible effect is that the prefixes on
those console-based fatal error messages will now be more consistent
between applications.)
2018-10-11 18:58:42 +00:00
|
|
|
s->userpass_ret = seat_get_userpass_input(
|
|
|
|
s->ppl.seat, s->cur_prompt, NULL);
|
Move most of ssh.c out into separate source files.
I've tried to separate out as many individually coherent changes from
this work as I could into their own commits, but here's where I run
out and have to commit the rest of this major refactoring as a
big-bang change.
Most of ssh.c is now no longer in ssh.c: all five of the main
coroutines that handle layers of the SSH-1 and SSH-2 protocols now
each have their own source file to live in, and a lot of the
supporting functions have moved into the appropriate one of those too.
The new abstraction is a vtable called 'PacketProtocolLayer', which
has an input and output packet queue. Each layer's main coroutine is
invoked from the method ssh_ppl_process_queue(), which is usually
(though not exclusively) triggered automatically when things are
pushed on the input queue. In SSH-2, the base layer is the transport
protocol, and it contains a pair of subsidiary queues by which it
passes some of its packets to the higher SSH-2 layers - first userauth
and then connection, which are peers at the same level, with the
former abdicating in favour of the latter at the appropriate moment.
SSH-1 is simpler: the whole login phase of the protocol (crypto setup
and authentication) is all in one module, and since SSH-1 has no
repeat key exchange, that setup layer abdicates in favour of the
connection phase when it's done.
ssh.c itself is now about a tenth of its old size (which all by itself
is cause for celebration!). Its main job is to set up all the layers,
hook them up to each other and to the BPP, and to funnel data back and
forth between that collection of modules and external things such as
the network and the terminal. Once it's set up a collection of packet
protocol layers, it communicates with them partly by calling methods
of the base layer (and if that's ssh2transport then it will delegate
some functionality to the corresponding methods of its higher layer),
and partly by talking directly to the connection layer no matter where
it is in the stack by means of the separate ConnectionLayer vtable
which I introduced in commit 8001dd4cb, and to which I've now added
quite a few extra methods replacing services that used to be internal
function calls within ssh.c.
(One effect of this is that the SSH-1 and SSH-2 channel storage is now
no longer shared - there are distinct struct types ssh1_channel and
ssh2_channel. That means a bit more code duplication, but on the plus
side, a lot fewer confusing conditionals in the middle of half-shared
functions, and less risk of a piece of SSH-1 escaping into SSH-2 or
vice versa, which I remember has happened at least once in the past.)
The bulk of this commit introduces the five new source files, their
common header sshppl.h and some shared supporting routines in
sshcommon.c, and rewrites nearly all of ssh.c itself. But it also
includes a couple of other changes that I couldn't separate easily
enough:
Firstly, there's a new handling for socket EOF, in which ssh.c sets an
'input_eof' flag in the BPP, and that responds by checking a flag that
tells it whether to report the EOF as an error or not. (This is the
main reason for those new BPP_READ / BPP_WAITFOR macros - they can
check the EOF flag every time the coroutine is resumed.)
Secondly, the error reporting itself is changed around again. I'd
expected to put some data fields in the public PacketProtocolLayer
structure that it could set to report errors in the same way as the
BPPs have been doing, but in the end, I decided propagating all those
data fields around was a pain and that even the BPPs shouldn't have
been doing it that way. So I've reverted to a system where everything
calls back to functions in ssh.c itself to report any connection-
ending condition. But there's a new family of those functions,
categorising the possible such conditions by semantics, and each one
has a different set of detailed effects (e.g. how rudely to close the
network connection, what exit status should be passed back to the
whole application, whether to send a disconnect message and/or display
a GUI error box).
I don't expect this to be immediately perfect: of course, the code has
been through a big upheaval, new bugs are expected, and I haven't been
able to do a full job of testing (e.g. I haven't tested every auth or
kex method). But I've checked that it _basically_ works - both SSH
protocols, all the different kinds of forwarding channel, more than
one auth method, Windows and Linux, connection sharing - and I think
it's now at the point where the easiest way to find further bugs is to
let it out into the wild and see what users can spot.
2018-09-24 17:28:16 +00:00
|
|
|
while (1) {
|
|
|
|
while (s->userpass_ret < 0 &&
|
|
|
|
bufchain_size(s->ppl.user_input) > 0)
|
New abstraction 'Seat', to pass to backends.
This is a new vtable-based abstraction which is passed to a backend in
place of Frontend, and it implements only the subset of the Frontend
functions needed by a backend. (Many other Frontend functions still
exist, notably the wide range of things called by terminal.c providing
platform-independent operations on the GUI terminal window.)
The purpose of making it a vtable is that this opens up the
possibility of creating a backend as an internal implementation detail
of some other activity, by providing just that one backend with a
custom Seat that implements the methods differently.
For example, this refactoring should make it feasible to directly
implement an SSH proxy type, aka the 'jump host' feature supported by
OpenSSH, aka 'open a secondary SSH session in MAINCHAN_DIRECT_TCP
mode, and then expose the main channel of that as the Socket for the
primary connection'. (Which of course you can already do by spawning
'plink -nc' as a separate proxy process, but this would permit it in
the _same_ process without anything getting confused.)
I've centralised a full set of stub methods in misc.c for the new
abstraction, which allows me to get rid of several annoying stubs in
the previous code. Also, while I'm here, I've moved a lot of
duplicated modalfatalbox() type functions from application main
program files into wincons.c / uxcons.c, which I think saves
duplication overall. (A minor visible effect is that the prefixes on
those console-based fatal error messages will now be more consistent
between applications.)
2018-10-11 18:58:42 +00:00
|
|
|
s->userpass_ret = seat_get_userpass_input(
|
|
|
|
s->ppl.seat, s->cur_prompt, s->ppl.user_input);
|
Move most of ssh.c out into separate source files.
I've tried to separate out as many individually coherent changes from
this work as I could into their own commits, but here's where I run
out and have to commit the rest of this major refactoring as a
big-bang change.
Most of ssh.c is now no longer in ssh.c: all five of the main
coroutines that handle layers of the SSH-1 and SSH-2 protocols now
each have their own source file to live in, and a lot of the
supporting functions have moved into the appropriate one of those too.
The new abstraction is a vtable called 'PacketProtocolLayer', which
has an input and output packet queue. Each layer's main coroutine is
invoked from the method ssh_ppl_process_queue(), which is usually
(though not exclusively) triggered automatically when things are
pushed on the input queue. In SSH-2, the base layer is the transport
protocol, and it contains a pair of subsidiary queues by which it
passes some of its packets to the higher SSH-2 layers - first userauth
and then connection, which are peers at the same level, with the
former abdicating in favour of the latter at the appropriate moment.
SSH-1 is simpler: the whole login phase of the protocol (crypto setup
and authentication) is all in one module, and since SSH-1 has no
repeat key exchange, that setup layer abdicates in favour of the
connection phase when it's done.
ssh.c itself is now about a tenth of its old size (which all by itself
is cause for celebration!). Its main job is to set up all the layers,
hook them up to each other and to the BPP, and to funnel data back and
forth between that collection of modules and external things such as
the network and the terminal. Once it's set up a collection of packet
protocol layers, it communicates with them partly by calling methods
of the base layer (and if that's ssh2transport then it will delegate
some functionality to the corresponding methods of its higher layer),
and partly by talking directly to the connection layer no matter where
it is in the stack by means of the separate ConnectionLayer vtable
which I introduced in commit 8001dd4cb, and to which I've now added
quite a few extra methods replacing services that used to be internal
function calls within ssh.c.
(One effect of this is that the SSH-1 and SSH-2 channel storage is now
no longer shared - there are distinct struct types ssh1_channel and
ssh2_channel. That means a bit more code duplication, but on the plus
side, a lot fewer confusing conditionals in the middle of half-shared
functions, and less risk of a piece of SSH-1 escaping into SSH-2 or
vice versa, which I remember has happened at least once in the past.)
The bulk of this commit introduces the five new source files, their
common header sshppl.h and some shared supporting routines in
sshcommon.c, and rewrites nearly all of ssh.c itself. But it also
includes a couple of other changes that I couldn't separate easily
enough:
Firstly, there's a new handling for socket EOF, in which ssh.c sets an
'input_eof' flag in the BPP, and that responds by checking a flag that
tells it whether to report the EOF as an error or not. (This is the
main reason for those new BPP_READ / BPP_WAITFOR macros - they can
check the EOF flag every time the coroutine is resumed.)
Secondly, the error reporting itself is changed around again. I'd
expected to put some data fields in the public PacketProtocolLayer
structure that it could set to report errors in the same way as the
BPPs have been doing, but in the end, I decided propagating all those
data fields around was a pain and that even the BPPs shouldn't have
been doing it that way. So I've reverted to a system where everything
calls back to functions in ssh.c itself to report any connection-
ending condition. But there's a new family of those functions,
categorising the possible such conditions by semantics, and each one
has a different set of detailed effects (e.g. how rudely to close the
network connection, what exit status should be passed back to the
whole application, whether to send a disconnect message and/or display
a GUI error box).
I don't expect this to be immediately perfect: of course, the code has
been through a big upheaval, new bugs are expected, and I haven't been
able to do a full job of testing (e.g. I haven't tested every auth or
kex method). But I've checked that it _basically_ works - both SSH
protocols, all the different kinds of forwarding channel, more than
one auth method, Windows and Linux, connection sharing - and I think
it's now at the point where the easiest way to find further bugs is to
let it out into the wild and see what users can spot.
2018-09-24 17:28:16 +00:00
|
|
|
|
|
|
|
if (s->userpass_ret >= 0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
s->want_user_input = TRUE;
|
|
|
|
crReturnV;
|
|
|
|
s->want_user_input = FALSE;
|
|
|
|
}
|
|
|
|
if (!s->userpass_ret) {
|
|
|
|
/*
|
|
|
|
* Failed to get responses. Terminate.
|
|
|
|
*/
|
|
|
|
free_prompts(s->cur_prompt);
|
|
|
|
ssh_bpp_queue_disconnect(
|
|
|
|
s->ppl.bpp, "Unable to authenticate",
|
|
|
|
SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER);
|
|
|
|
ssh_user_close(s->ppl.ssh, "User aborted during password "
|
|
|
|
"authentication");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* Squirrel away the password. (We may need it later if
|
|
|
|
* asked to change it.)
|
|
|
|
*/
|
|
|
|
s->password = dupstr(s->cur_prompt->prompts[0]->result);
|
|
|
|
free_prompts(s->cur_prompt);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Send the password packet.
|
|
|
|
*
|
|
|
|
* We pad out the password packet to 256 bytes to make
|
|
|
|
* it harder for an attacker to find the length of the
|
|
|
|
* user's password.
|
|
|
|
*
|
|
|
|
* Anyone using a password longer than 256 bytes
|
|
|
|
* probably doesn't have much to worry about from
|
|
|
|
* people who find out how long their password is!
|
|
|
|
*/
|
|
|
|
s->pktout = ssh_bpp_new_pktout(
|
|
|
|
s->ppl.bpp, SSH2_MSG_USERAUTH_REQUEST);
|
|
|
|
put_stringz(s->pktout, s->username);
|
2018-10-09 17:11:17 +00:00
|
|
|
put_stringz(s->pktout, s->successor_layer->vt->name);
|
Move most of ssh.c out into separate source files.
I've tried to separate out as many individually coherent changes from
this work as I could into their own commits, but here's where I run
out and have to commit the rest of this major refactoring as a
big-bang change.
Most of ssh.c is now no longer in ssh.c: all five of the main
coroutines that handle layers of the SSH-1 and SSH-2 protocols now
each have their own source file to live in, and a lot of the
supporting functions have moved into the appropriate one of those too.
The new abstraction is a vtable called 'PacketProtocolLayer', which
has an input and output packet queue. Each layer's main coroutine is
invoked from the method ssh_ppl_process_queue(), which is usually
(though not exclusively) triggered automatically when things are
pushed on the input queue. In SSH-2, the base layer is the transport
protocol, and it contains a pair of subsidiary queues by which it
passes some of its packets to the higher SSH-2 layers - first userauth
and then connection, which are peers at the same level, with the
former abdicating in favour of the latter at the appropriate moment.
SSH-1 is simpler: the whole login phase of the protocol (crypto setup
and authentication) is all in one module, and since SSH-1 has no
repeat key exchange, that setup layer abdicates in favour of the
connection phase when it's done.
ssh.c itself is now about a tenth of its old size (which all by itself
is cause for celebration!). Its main job is to set up all the layers,
hook them up to each other and to the BPP, and to funnel data back and
forth between that collection of modules and external things such as
the network and the terminal. Once it's set up a collection of packet
protocol layers, it communicates with them partly by calling methods
of the base layer (and if that's ssh2transport then it will delegate
some functionality to the corresponding methods of its higher layer),
and partly by talking directly to the connection layer no matter where
it is in the stack by means of the separate ConnectionLayer vtable
which I introduced in commit 8001dd4cb, and to which I've now added
quite a few extra methods replacing services that used to be internal
function calls within ssh.c.
(One effect of this is that the SSH-1 and SSH-2 channel storage is now
no longer shared - there are distinct struct types ssh1_channel and
ssh2_channel. That means a bit more code duplication, but on the plus
side, a lot fewer confusing conditionals in the middle of half-shared
functions, and less risk of a piece of SSH-1 escaping into SSH-2 or
vice versa, which I remember has happened at least once in the past.)
The bulk of this commit introduces the five new source files, their
common header sshppl.h and some shared supporting routines in
sshcommon.c, and rewrites nearly all of ssh.c itself. But it also
includes a couple of other changes that I couldn't separate easily
enough:
Firstly, there's a new handling for socket EOF, in which ssh.c sets an
'input_eof' flag in the BPP, and that responds by checking a flag that
tells it whether to report the EOF as an error or not. (This is the
main reason for those new BPP_READ / BPP_WAITFOR macros - they can
check the EOF flag every time the coroutine is resumed.)
Secondly, the error reporting itself is changed around again. I'd
expected to put some data fields in the public PacketProtocolLayer
structure that it could set to report errors in the same way as the
BPPs have been doing, but in the end, I decided propagating all those
data fields around was a pain and that even the BPPs shouldn't have
been doing it that way. So I've reverted to a system where everything
calls back to functions in ssh.c itself to report any connection-
ending condition. But there's a new family of those functions,
categorising the possible such conditions by semantics, and each one
has a different set of detailed effects (e.g. how rudely to close the
network connection, what exit status should be passed back to the
whole application, whether to send a disconnect message and/or display
a GUI error box).
I don't expect this to be immediately perfect: of course, the code has
been through a big upheaval, new bugs are expected, and I haven't been
able to do a full job of testing (e.g. I haven't tested every auth or
kex method). But I've checked that it _basically_ works - both SSH
protocols, all the different kinds of forwarding channel, more than
one auth method, Windows and Linux, connection sharing - and I think
it's now at the point where the easiest way to find further bugs is to
let it out into the wild and see what users can spot.
2018-09-24 17:28:16 +00:00
|
|
|
put_stringz(s->pktout, "password");
|
|
|
|
put_bool(s->pktout, FALSE);
|
|
|
|
put_stringz(s->pktout, s->password);
|
|
|
|
s->pktout->minlen = 256;
|
|
|
|
pq_push(s->ppl.out_pq, s->pktout);
|
|
|
|
ppl_logevent(("Sent password"));
|
|
|
|
s->type = AUTH_TYPE_PASSWORD;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Wait for next packet, in case it's a password change
|
|
|
|
* request.
|
|
|
|
*/
|
|
|
|
crMaybeWaitUntilV((pktin = ssh2_userauth_pop(s)) != NULL);
|
|
|
|
changereq_first_time = TRUE;
|
|
|
|
|
|
|
|
while (pktin->type == SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ) {
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We're being asked for a new password
|
|
|
|
* (perhaps not for the first time).
|
|
|
|
* Loop until the server accepts it.
|
|
|
|
*/
|
|
|
|
|
|
|
|
int got_new = FALSE; /* not live over crReturn */
|
|
|
|
ptrlen prompt; /* not live over crReturn */
|
|
|
|
|
|
|
|
{
|
|
|
|
const char *msg;
|
|
|
|
if (changereq_first_time)
|
|
|
|
msg = "Server requested password change";
|
|
|
|
else
|
|
|
|
msg = "Server rejected new password";
|
|
|
|
ppl_logevent(("%s", msg));
|
|
|
|
ppl_printf(("%s\r\n", msg));
|
|
|
|
}
|
|
|
|
|
|
|
|
prompt = get_string(pktin);
|
|
|
|
|
New abstraction 'Seat', to pass to backends.
This is a new vtable-based abstraction which is passed to a backend in
place of Frontend, and it implements only the subset of the Frontend
functions needed by a backend. (Many other Frontend functions still
exist, notably the wide range of things called by terminal.c providing
platform-independent operations on the GUI terminal window.)
The purpose of making it a vtable is that this opens up the
possibility of creating a backend as an internal implementation detail
of some other activity, by providing just that one backend with a
custom Seat that implements the methods differently.
For example, this refactoring should make it feasible to directly
implement an SSH proxy type, aka the 'jump host' feature supported by
OpenSSH, aka 'open a secondary SSH session in MAINCHAN_DIRECT_TCP
mode, and then expose the main channel of that as the Socket for the
primary connection'. (Which of course you can already do by spawning
'plink -nc' as a separate proxy process, but this would permit it in
the _same_ process without anything getting confused.)
I've centralised a full set of stub methods in misc.c for the new
abstraction, which allows me to get rid of several annoying stubs in
the previous code. Also, while I'm here, I've moved a lot of
duplicated modalfatalbox() type functions from application main
program files into wincons.c / uxcons.c, which I think saves
duplication overall. (A minor visible effect is that the prefixes on
those console-based fatal error messages will now be more consistent
between applications.)
2018-10-11 18:58:42 +00:00
|
|
|
s->cur_prompt = new_prompts();
|
Move most of ssh.c out into separate source files.
I've tried to separate out as many individually coherent changes from
this work as I could into their own commits, but here's where I run
out and have to commit the rest of this major refactoring as a
big-bang change.
Most of ssh.c is now no longer in ssh.c: all five of the main
coroutines that handle layers of the SSH-1 and SSH-2 protocols now
each have their own source file to live in, and a lot of the
supporting functions have moved into the appropriate one of those too.
The new abstraction is a vtable called 'PacketProtocolLayer', which
has an input and output packet queue. Each layer's main coroutine is
invoked from the method ssh_ppl_process_queue(), which is usually
(though not exclusively) triggered automatically when things are
pushed on the input queue. In SSH-2, the base layer is the transport
protocol, and it contains a pair of subsidiary queues by which it
passes some of its packets to the higher SSH-2 layers - first userauth
and then connection, which are peers at the same level, with the
former abdicating in favour of the latter at the appropriate moment.
SSH-1 is simpler: the whole login phase of the protocol (crypto setup
and authentication) is all in one module, and since SSH-1 has no
repeat key exchange, that setup layer abdicates in favour of the
connection phase when it's done.
ssh.c itself is now about a tenth of its old size (which all by itself
is cause for celebration!). Its main job is to set up all the layers,
hook them up to each other and to the BPP, and to funnel data back and
forth between that collection of modules and external things such as
the network and the terminal. Once it's set up a collection of packet
protocol layers, it communicates with them partly by calling methods
of the base layer (and if that's ssh2transport then it will delegate
some functionality to the corresponding methods of its higher layer),
and partly by talking directly to the connection layer no matter where
it is in the stack by means of the separate ConnectionLayer vtable
which I introduced in commit 8001dd4cb, and to which I've now added
quite a few extra methods replacing services that used to be internal
function calls within ssh.c.
(One effect of this is that the SSH-1 and SSH-2 channel storage is now
no longer shared - there are distinct struct types ssh1_channel and
ssh2_channel. That means a bit more code duplication, but on the plus
side, a lot fewer confusing conditionals in the middle of half-shared
functions, and less risk of a piece of SSH-1 escaping into SSH-2 or
vice versa, which I remember has happened at least once in the past.)
The bulk of this commit introduces the five new source files, their
common header sshppl.h and some shared supporting routines in
sshcommon.c, and rewrites nearly all of ssh.c itself. But it also
includes a couple of other changes that I couldn't separate easily
enough:
Firstly, there's a new handling for socket EOF, in which ssh.c sets an
'input_eof' flag in the BPP, and that responds by checking a flag that
tells it whether to report the EOF as an error or not. (This is the
main reason for those new BPP_READ / BPP_WAITFOR macros - they can
check the EOF flag every time the coroutine is resumed.)
Secondly, the error reporting itself is changed around again. I'd
expected to put some data fields in the public PacketProtocolLayer
structure that it could set to report errors in the same way as the
BPPs have been doing, but in the end, I decided propagating all those
data fields around was a pain and that even the BPPs shouldn't have
been doing it that way. So I've reverted to a system where everything
calls back to functions in ssh.c itself to report any connection-
ending condition. But there's a new family of those functions,
categorising the possible such conditions by semantics, and each one
has a different set of detailed effects (e.g. how rudely to close the
network connection, what exit status should be passed back to the
whole application, whether to send a disconnect message and/or display
a GUI error box).
I don't expect this to be immediately perfect: of course, the code has
been through a big upheaval, new bugs are expected, and I haven't been
able to do a full job of testing (e.g. I haven't tested every auth or
kex method). But I've checked that it _basically_ works - both SSH
protocols, all the different kinds of forwarding channel, more than
one auth method, Windows and Linux, connection sharing - and I think
it's now at the point where the easiest way to find further bugs is to
let it out into the wild and see what users can spot.
2018-09-24 17:28:16 +00:00
|
|
|
s->cur_prompt->to_server = TRUE;
|
|
|
|
s->cur_prompt->name = dupstr("New SSH password");
|
|
|
|
s->cur_prompt->instruction = mkstr(prompt);
|
|
|
|
s->cur_prompt->instr_reqd = TRUE;
|
|
|
|
/*
|
|
|
|
* There's no explicit requirement in the protocol
|
|
|
|
* for the "old" passwords in the original and
|
|
|
|
* password-change messages to be the same, and
|
|
|
|
* apparently some Cisco kit supports password change
|
|
|
|
* by the user entering a blank password originally
|
|
|
|
* and the real password subsequently, so,
|
|
|
|
* reluctantly, we prompt for the old password again.
|
|
|
|
*
|
|
|
|
* (On the other hand, some servers don't even bother
|
|
|
|
* to check this field.)
|
|
|
|
*/
|
|
|
|
add_prompt(s->cur_prompt,
|
|
|
|
dupstr("Current password (blank for previously entered password): "),
|
|
|
|
FALSE);
|
|
|
|
add_prompt(s->cur_prompt, dupstr("Enter new password: "),
|
|
|
|
FALSE);
|
|
|
|
add_prompt(s->cur_prompt, dupstr("Confirm new password: "),
|
|
|
|
FALSE);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Loop until the user manages to enter the same
|
|
|
|
* password twice.
|
|
|
|
*/
|
|
|
|
while (!got_new) {
|
New abstraction 'Seat', to pass to backends.
This is a new vtable-based abstraction which is passed to a backend in
place of Frontend, and it implements only the subset of the Frontend
functions needed by a backend. (Many other Frontend functions still
exist, notably the wide range of things called by terminal.c providing
platform-independent operations on the GUI terminal window.)
The purpose of making it a vtable is that this opens up the
possibility of creating a backend as an internal implementation detail
of some other activity, by providing just that one backend with a
custom Seat that implements the methods differently.
For example, this refactoring should make it feasible to directly
implement an SSH proxy type, aka the 'jump host' feature supported by
OpenSSH, aka 'open a secondary SSH session in MAINCHAN_DIRECT_TCP
mode, and then expose the main channel of that as the Socket for the
primary connection'. (Which of course you can already do by spawning
'plink -nc' as a separate proxy process, but this would permit it in
the _same_ process without anything getting confused.)
I've centralised a full set of stub methods in misc.c for the new
abstraction, which allows me to get rid of several annoying stubs in
the previous code. Also, while I'm here, I've moved a lot of
duplicated modalfatalbox() type functions from application main
program files into wincons.c / uxcons.c, which I think saves
duplication overall. (A minor visible effect is that the prefixes on
those console-based fatal error messages will now be more consistent
between applications.)
2018-10-11 18:58:42 +00:00
|
|
|
s->userpass_ret = seat_get_userpass_input(
|
|
|
|
s->ppl.seat, s->cur_prompt, NULL);
|
Move most of ssh.c out into separate source files.
I've tried to separate out as many individually coherent changes from
this work as I could into their own commits, but here's where I run
out and have to commit the rest of this major refactoring as a
big-bang change.
Most of ssh.c is now no longer in ssh.c: all five of the main
coroutines that handle layers of the SSH-1 and SSH-2 protocols now
each have their own source file to live in, and a lot of the
supporting functions have moved into the appropriate one of those too.
The new abstraction is a vtable called 'PacketProtocolLayer', which
has an input and output packet queue. Each layer's main coroutine is
invoked from the method ssh_ppl_process_queue(), which is usually
(though not exclusively) triggered automatically when things are
pushed on the input queue. In SSH-2, the base layer is the transport
protocol, and it contains a pair of subsidiary queues by which it
passes some of its packets to the higher SSH-2 layers - first userauth
and then connection, which are peers at the same level, with the
former abdicating in favour of the latter at the appropriate moment.
SSH-1 is simpler: the whole login phase of the protocol (crypto setup
and authentication) is all in one module, and since SSH-1 has no
repeat key exchange, that setup layer abdicates in favour of the
connection phase when it's done.
ssh.c itself is now about a tenth of its old size (which all by itself
is cause for celebration!). Its main job is to set up all the layers,
hook them up to each other and to the BPP, and to funnel data back and
forth between that collection of modules and external things such as
the network and the terminal. Once it's set up a collection of packet
protocol layers, it communicates with them partly by calling methods
of the base layer (and if that's ssh2transport then it will delegate
some functionality to the corresponding methods of its higher layer),
and partly by talking directly to the connection layer no matter where
it is in the stack by means of the separate ConnectionLayer vtable
which I introduced in commit 8001dd4cb, and to which I've now added
quite a few extra methods replacing services that used to be internal
function calls within ssh.c.
(One effect of this is that the SSH-1 and SSH-2 channel storage is now
no longer shared - there are distinct struct types ssh1_channel and
ssh2_channel. That means a bit more code duplication, but on the plus
side, a lot fewer confusing conditionals in the middle of half-shared
functions, and less risk of a piece of SSH-1 escaping into SSH-2 or
vice versa, which I remember has happened at least once in the past.)
The bulk of this commit introduces the five new source files, their
common header sshppl.h and some shared supporting routines in
sshcommon.c, and rewrites nearly all of ssh.c itself. But it also
includes a couple of other changes that I couldn't separate easily
enough:
Firstly, there's a new handling for socket EOF, in which ssh.c sets an
'input_eof' flag in the BPP, and that responds by checking a flag that
tells it whether to report the EOF as an error or not. (This is the
main reason for those new BPP_READ / BPP_WAITFOR macros - they can
check the EOF flag every time the coroutine is resumed.)
Secondly, the error reporting itself is changed around again. I'd
expected to put some data fields in the public PacketProtocolLayer
structure that it could set to report errors in the same way as the
BPPs have been doing, but in the end, I decided propagating all those
data fields around was a pain and that even the BPPs shouldn't have
been doing it that way. So I've reverted to a system where everything
calls back to functions in ssh.c itself to report any connection-
ending condition. But there's a new family of those functions,
categorising the possible such conditions by semantics, and each one
has a different set of detailed effects (e.g. how rudely to close the
network connection, what exit status should be passed back to the
whole application, whether to send a disconnect message and/or display
a GUI error box).
I don't expect this to be immediately perfect: of course, the code has
been through a big upheaval, new bugs are expected, and I haven't been
able to do a full job of testing (e.g. I haven't tested every auth or
kex method). But I've checked that it _basically_ works - both SSH
protocols, all the different kinds of forwarding channel, more than
one auth method, Windows and Linux, connection sharing - and I think
it's now at the point where the easiest way to find further bugs is to
let it out into the wild and see what users can spot.
2018-09-24 17:28:16 +00:00
|
|
|
while (1) {
|
|
|
|
while (s->userpass_ret < 0 &&
|
|
|
|
bufchain_size(s->ppl.user_input) > 0)
|
New abstraction 'Seat', to pass to backends.
This is a new vtable-based abstraction which is passed to a backend in
place of Frontend, and it implements only the subset of the Frontend
functions needed by a backend. (Many other Frontend functions still
exist, notably the wide range of things called by terminal.c providing
platform-independent operations on the GUI terminal window.)
The purpose of making it a vtable is that this opens up the
possibility of creating a backend as an internal implementation detail
of some other activity, by providing just that one backend with a
custom Seat that implements the methods differently.
For example, this refactoring should make it feasible to directly
implement an SSH proxy type, aka the 'jump host' feature supported by
OpenSSH, aka 'open a secondary SSH session in MAINCHAN_DIRECT_TCP
mode, and then expose the main channel of that as the Socket for the
primary connection'. (Which of course you can already do by spawning
'plink -nc' as a separate proxy process, but this would permit it in
the _same_ process without anything getting confused.)
I've centralised a full set of stub methods in misc.c for the new
abstraction, which allows me to get rid of several annoying stubs in
the previous code. Also, while I'm here, I've moved a lot of
duplicated modalfatalbox() type functions from application main
program files into wincons.c / uxcons.c, which I think saves
duplication overall. (A minor visible effect is that the prefixes on
those console-based fatal error messages will now be more consistent
between applications.)
2018-10-11 18:58:42 +00:00
|
|
|
s->userpass_ret = seat_get_userpass_input(
|
|
|
|
s->ppl.seat, s->cur_prompt,
|
|
|
|
s->ppl.user_input);
|
Move most of ssh.c out into separate source files.
I've tried to separate out as many individually coherent changes from
this work as I could into their own commits, but here's where I run
out and have to commit the rest of this major refactoring as a
big-bang change.
Most of ssh.c is now no longer in ssh.c: all five of the main
coroutines that handle layers of the SSH-1 and SSH-2 protocols now
each have their own source file to live in, and a lot of the
supporting functions have moved into the appropriate one of those too.
The new abstraction is a vtable called 'PacketProtocolLayer', which
has an input and output packet queue. Each layer's main coroutine is
invoked from the method ssh_ppl_process_queue(), which is usually
(though not exclusively) triggered automatically when things are
pushed on the input queue. In SSH-2, the base layer is the transport
protocol, and it contains a pair of subsidiary queues by which it
passes some of its packets to the higher SSH-2 layers - first userauth
and then connection, which are peers at the same level, with the
former abdicating in favour of the latter at the appropriate moment.
SSH-1 is simpler: the whole login phase of the protocol (crypto setup
and authentication) is all in one module, and since SSH-1 has no
repeat key exchange, that setup layer abdicates in favour of the
connection phase when it's done.
ssh.c itself is now about a tenth of its old size (which all by itself
is cause for celebration!). Its main job is to set up all the layers,
hook them up to each other and to the BPP, and to funnel data back and
forth between that collection of modules and external things such as
the network and the terminal. Once it's set up a collection of packet
protocol layers, it communicates with them partly by calling methods
of the base layer (and if that's ssh2transport then it will delegate
some functionality to the corresponding methods of its higher layer),
and partly by talking directly to the connection layer no matter where
it is in the stack by means of the separate ConnectionLayer vtable
which I introduced in commit 8001dd4cb, and to which I've now added
quite a few extra methods replacing services that used to be internal
function calls within ssh.c.
(One effect of this is that the SSH-1 and SSH-2 channel storage is now
no longer shared - there are distinct struct types ssh1_channel and
ssh2_channel. That means a bit more code duplication, but on the plus
side, a lot fewer confusing conditionals in the middle of half-shared
functions, and less risk of a piece of SSH-1 escaping into SSH-2 or
vice versa, which I remember has happened at least once in the past.)
The bulk of this commit introduces the five new source files, their
common header sshppl.h and some shared supporting routines in
sshcommon.c, and rewrites nearly all of ssh.c itself. But it also
includes a couple of other changes that I couldn't separate easily
enough:
Firstly, there's a new handling for socket EOF, in which ssh.c sets an
'input_eof' flag in the BPP, and that responds by checking a flag that
tells it whether to report the EOF as an error or not. (This is the
main reason for those new BPP_READ / BPP_WAITFOR macros - they can
check the EOF flag every time the coroutine is resumed.)
Secondly, the error reporting itself is changed around again. I'd
expected to put some data fields in the public PacketProtocolLayer
structure that it could set to report errors in the same way as the
BPPs have been doing, but in the end, I decided propagating all those
data fields around was a pain and that even the BPPs shouldn't have
been doing it that way. So I've reverted to a system where everything
calls back to functions in ssh.c itself to report any connection-
ending condition. But there's a new family of those functions,
categorising the possible such conditions by semantics, and each one
has a different set of detailed effects (e.g. how rudely to close the
network connection, what exit status should be passed back to the
whole application, whether to send a disconnect message and/or display
a GUI error box).
I don't expect this to be immediately perfect: of course, the code has
been through a big upheaval, new bugs are expected, and I haven't been
able to do a full job of testing (e.g. I haven't tested every auth or
kex method). But I've checked that it _basically_ works - both SSH
protocols, all the different kinds of forwarding channel, more than
one auth method, Windows and Linux, connection sharing - and I think
it's now at the point where the easiest way to find further bugs is to
let it out into the wild and see what users can spot.
2018-09-24 17:28:16 +00:00
|
|
|
|
|
|
|
if (s->userpass_ret >= 0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
s->want_user_input = TRUE;
|
|
|
|
crReturnV;
|
|
|
|
s->want_user_input = FALSE;
|
|
|
|
}
|
|
|
|
if (!s->userpass_ret) {
|
|
|
|
/*
|
|
|
|
* Failed to get responses. Terminate.
|
|
|
|
*/
|
|
|
|
/* burn the evidence */
|
|
|
|
free_prompts(s->cur_prompt);
|
|
|
|
smemclr(s->password, strlen(s->password));
|
|
|
|
sfree(s->password);
|
|
|
|
ssh_bpp_queue_disconnect(
|
|
|
|
s->ppl.bpp, "Unable to authenticate",
|
|
|
|
SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER);
|
|
|
|
ssh_user_close(s->ppl.ssh, "User aborted during "
|
|
|
|
"password changing");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If the user specified a new original password
|
|
|
|
* (IYSWIM), overwrite any previously specified
|
|
|
|
* one.
|
|
|
|
* (A side effect is that the user doesn't have to
|
|
|
|
* re-enter it if they louse up the new password.)
|
|
|
|
*/
|
|
|
|
if (s->cur_prompt->prompts[0]->result[0]) {
|
|
|
|
smemclr(s->password, strlen(s->password));
|
|
|
|
/* burn the evidence */
|
|
|
|
sfree(s->password);
|
|
|
|
s->password =
|
|
|
|
dupstr(s->cur_prompt->prompts[0]->result);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check the two new passwords match.
|
|
|
|
*/
|
|
|
|
got_new = (strcmp(s->cur_prompt->prompts[1]->result,
|
|
|
|
s->cur_prompt->prompts[2]->result)
|
|
|
|
== 0);
|
|
|
|
if (!got_new)
|
|
|
|
/* They don't. Silly user. */
|
|
|
|
ppl_printf(("Passwords do not match\r\n"));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Send the new password (along with the old one).
|
|
|
|
* (see above for padding rationale)
|
|
|
|
*/
|
|
|
|
s->pktout = ssh_bpp_new_pktout(
|
|
|
|
s->ppl.bpp, SSH2_MSG_USERAUTH_REQUEST);
|
|
|
|
put_stringz(s->pktout, s->username);
|
2018-10-09 17:11:17 +00:00
|
|
|
put_stringz(s->pktout, s->successor_layer->vt->name);
|
Move most of ssh.c out into separate source files.
I've tried to separate out as many individually coherent changes from
this work as I could into their own commits, but here's where I run
out and have to commit the rest of this major refactoring as a
big-bang change.
Most of ssh.c is now no longer in ssh.c: all five of the main
coroutines that handle layers of the SSH-1 and SSH-2 protocols now
each have their own source file to live in, and a lot of the
supporting functions have moved into the appropriate one of those too.
The new abstraction is a vtable called 'PacketProtocolLayer', which
has an input and output packet queue. Each layer's main coroutine is
invoked from the method ssh_ppl_process_queue(), which is usually
(though not exclusively) triggered automatically when things are
pushed on the input queue. In SSH-2, the base layer is the transport
protocol, and it contains a pair of subsidiary queues by which it
passes some of its packets to the higher SSH-2 layers - first userauth
and then connection, which are peers at the same level, with the
former abdicating in favour of the latter at the appropriate moment.
SSH-1 is simpler: the whole login phase of the protocol (crypto setup
and authentication) is all in one module, and since SSH-1 has no
repeat key exchange, that setup layer abdicates in favour of the
connection phase when it's done.
ssh.c itself is now about a tenth of its old size (which all by itself
is cause for celebration!). Its main job is to set up all the layers,
hook them up to each other and to the BPP, and to funnel data back and
forth between that collection of modules and external things such as
the network and the terminal. Once it's set up a collection of packet
protocol layers, it communicates with them partly by calling methods
of the base layer (and if that's ssh2transport then it will delegate
some functionality to the corresponding methods of its higher layer),
and partly by talking directly to the connection layer no matter where
it is in the stack by means of the separate ConnectionLayer vtable
which I introduced in commit 8001dd4cb, and to which I've now added
quite a few extra methods replacing services that used to be internal
function calls within ssh.c.
(One effect of this is that the SSH-1 and SSH-2 channel storage is now
no longer shared - there are distinct struct types ssh1_channel and
ssh2_channel. That means a bit more code duplication, but on the plus
side, a lot fewer confusing conditionals in the middle of half-shared
functions, and less risk of a piece of SSH-1 escaping into SSH-2 or
vice versa, which I remember has happened at least once in the past.)
The bulk of this commit introduces the five new source files, their
common header sshppl.h and some shared supporting routines in
sshcommon.c, and rewrites nearly all of ssh.c itself. But it also
includes a couple of other changes that I couldn't separate easily
enough:
Firstly, there's a new handling for socket EOF, in which ssh.c sets an
'input_eof' flag in the BPP, and that responds by checking a flag that
tells it whether to report the EOF as an error or not. (This is the
main reason for those new BPP_READ / BPP_WAITFOR macros - they can
check the EOF flag every time the coroutine is resumed.)
Secondly, the error reporting itself is changed around again. I'd
expected to put some data fields in the public PacketProtocolLayer
structure that it could set to report errors in the same way as the
BPPs have been doing, but in the end, I decided propagating all those
data fields around was a pain and that even the BPPs shouldn't have
been doing it that way. So I've reverted to a system where everything
calls back to functions in ssh.c itself to report any connection-
ending condition. But there's a new family of those functions,
categorising the possible such conditions by semantics, and each one
has a different set of detailed effects (e.g. how rudely to close the
network connection, what exit status should be passed back to the
whole application, whether to send a disconnect message and/or display
a GUI error box).
I don't expect this to be immediately perfect: of course, the code has
been through a big upheaval, new bugs are expected, and I haven't been
able to do a full job of testing (e.g. I haven't tested every auth or
kex method). But I've checked that it _basically_ works - both SSH
protocols, all the different kinds of forwarding channel, more than
one auth method, Windows and Linux, connection sharing - and I think
it's now at the point where the easiest way to find further bugs is to
let it out into the wild and see what users can spot.
2018-09-24 17:28:16 +00:00
|
|
|
put_stringz(s->pktout, "password");
|
|
|
|
put_bool(s->pktout, TRUE);
|
|
|
|
put_stringz(s->pktout, s->password);
|
|
|
|
put_stringz(s->pktout,
|
|
|
|
s->cur_prompt->prompts[1]->result);
|
|
|
|
free_prompts(s->cur_prompt);
|
|
|
|
s->pktout->minlen = 256;
|
|
|
|
pq_push(s->ppl.out_pq, s->pktout);
|
|
|
|
ppl_logevent(("Sent new password"));
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Now see what the server has to say about it.
|
|
|
|
* (If it's CHANGEREQ again, it's not happy with the
|
|
|
|
* new password.)
|
|
|
|
*/
|
|
|
|
crMaybeWaitUntilV((pktin = ssh2_userauth_pop(s)) != NULL);
|
|
|
|
changereq_first_time = FALSE;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We need to reexamine the current pktin at the top
|
|
|
|
* of the loop. Either:
|
|
|
|
* - we weren't asked to change password at all, in
|
|
|
|
* which case it's a SUCCESS or FAILURE with the
|
|
|
|
* usual meaning
|
|
|
|
* - we sent a new password, and the server was
|
|
|
|
* either OK with it (SUCCESS or FAILURE w/partial
|
|
|
|
* success) or unhappy with the _old_ password
|
|
|
|
* (FAILURE w/o partial success)
|
|
|
|
* In any of these cases, we go back to the top of
|
|
|
|
* the loop and start again.
|
|
|
|
*/
|
|
|
|
pq_push_front(s->ppl.in_pq, pktin);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We don't need the old password any more, in any
|
|
|
|
* case. Burn the evidence.
|
|
|
|
*/
|
|
|
|
smemclr(s->password, strlen(s->password));
|
|
|
|
sfree(s->password);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
ssh_bpp_queue_disconnect(
|
|
|
|
s->ppl.bpp,
|
|
|
|
"No supported authentication methods available",
|
|
|
|
SSH2_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE);
|
|
|
|
ssh_sw_abort(s->ppl.ssh, "No supported authentication methods "
|
|
|
|
"available (server sent: %.*s)",
|
|
|
|
PTRLEN_PRINTF(methods));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
try_new_username:;
|
|
|
|
}
|
|
|
|
|
|
|
|
userauth_success:
|
|
|
|
/*
|
|
|
|
* We've just received USERAUTH_SUCCESS, and we haven't sent
|
|
|
|
* any packets since. Signal the transport layer to consider
|
|
|
|
* doing an immediate rekey, if it has any reason to want to.
|
|
|
|
*/
|
|
|
|
ssh2_transport_notify_auth_done(s->transport_layer);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Finally, hand over to our successor layer, and return
|
|
|
|
* immediately without reaching the crFinishV: ssh_ppl_replace
|
|
|
|
* will have freed us, so crFinishV's zeroing-out of crState would
|
|
|
|
* be a use-after-free bug.
|
|
|
|
*/
|
|
|
|
{
|
|
|
|
PacketProtocolLayer *successor = s->successor_layer;
|
|
|
|
s->successor_layer = NULL; /* avoid freeing it ourself */
|
|
|
|
ssh_ppl_replace(&s->ppl, successor);
|
|
|
|
return; /* we've just freed s, so avoid even touching s->crState */
|
|
|
|
}
|
|
|
|
|
|
|
|
crFinishV;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void ssh2_userauth_add_session_id(
|
|
|
|
struct ssh2_userauth_state *s, strbuf *sigdata)
|
|
|
|
{
|
|
|
|
if (s->ppl.remote_bugs & BUG_SSH2_PK_SESSIONID) {
|
|
|
|
put_data(sigdata, s->session_id.ptr, s->session_id.len);
|
|
|
|
} else {
|
|
|
|
put_stringpl(sigdata, s->session_id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void ssh2_userauth_agent_query(
|
|
|
|
struct ssh2_userauth_state *s, strbuf *req)
|
|
|
|
{
|
|
|
|
void *response;
|
|
|
|
int response_len;
|
|
|
|
|
|
|
|
sfree(s->agent_response_to_free);
|
|
|
|
s->agent_response_to_free = NULL;
|
|
|
|
|
|
|
|
s->auth_agent_query = agent_query(req, &response, &response_len,
|
|
|
|
ssh2_userauth_agent_callback, s);
|
|
|
|
if (!s->auth_agent_query)
|
|
|
|
ssh2_userauth_agent_callback(s, response, response_len);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void ssh2_userauth_agent_callback(void *uav, void *reply, int replylen)
|
|
|
|
{
|
|
|
|
struct ssh2_userauth_state *s = (struct ssh2_userauth_state *)uav;
|
|
|
|
|
|
|
|
s->auth_agent_query = NULL;
|
|
|
|
s->agent_response_to_free = reply;
|
|
|
|
s->agent_response = make_ptrlen(reply, replylen);
|
|
|
|
|
|
|
|
queue_idempotent_callback(&s->ppl.ic_process_queue);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Helper function to add an SSH-2 signature blob to a packet. Expects
|
|
|
|
* to be shown the public key blob as well as the signature blob.
|
|
|
|
* Normally just appends the sig blob unmodified as a string, except
|
|
|
|
* that it optionally breaks it open and fiddle with it to work around
|
|
|
|
* BUG_SSH2_RSA_PADDING.
|
|
|
|
*/
|
|
|
|
static void ssh2_userauth_add_sigblob(
|
|
|
|
struct ssh2_userauth_state *s, PktOut *pkt, ptrlen pkblob, ptrlen sigblob)
|
|
|
|
{
|
|
|
|
BinarySource pk[1], sig[1];
|
|
|
|
BinarySource_BARE_INIT(pk, pkblob.ptr, pkblob.len);
|
|
|
|
BinarySource_BARE_INIT(sig, sigblob.ptr, sigblob.len);
|
|
|
|
|
|
|
|
/* dmemdump(pkblob, pkblob_len); */
|
|
|
|
/* dmemdump(sigblob, sigblob_len); */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* See if this is in fact an ssh-rsa signature and a buggy
|
|
|
|
* server; otherwise we can just do this the easy way.
|
|
|
|
*/
|
|
|
|
if ((s->ppl.remote_bugs & BUG_SSH2_RSA_PADDING) &&
|
|
|
|
ptrlen_eq_string(get_string(pk), "ssh-rsa") &&
|
|
|
|
ptrlen_eq_string(get_string(sig), "ssh-rsa")) {
|
|
|
|
ptrlen mod_mp, sig_mp;
|
|
|
|
size_t sig_prefix_len;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Find the modulus and signature integers.
|
|
|
|
*/
|
|
|
|
get_string(pk); /* skip over exponent */
|
|
|
|
mod_mp = get_string(pk); /* remember modulus */
|
|
|
|
sig_prefix_len = sig->pos;
|
|
|
|
sig_mp = get_string(sig);
|
|
|
|
if (get_err(pk) || get_err(sig))
|
|
|
|
goto give_up;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Find the byte length of the modulus, not counting leading
|
|
|
|
* zeroes.
|
|
|
|
*/
|
|
|
|
while (mod_mp.len > 0 && *(const char *)mod_mp.ptr == 0) {
|
|
|
|
mod_mp.len--;
|
|
|
|
mod_mp.ptr = (const char *)mod_mp.ptr + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* debug(("modulus length is %d\n", len)); */
|
|
|
|
/* debug(("signature length is %d\n", siglen)); */
|
|
|
|
|
|
|
|
if (mod_mp.len != sig_mp.len) {
|
|
|
|
strbuf *substr = strbuf_new();
|
|
|
|
put_data(substr, sigblob.ptr, sig_prefix_len);
|
|
|
|
put_uint32(substr, mod_mp.len);
|
|
|
|
put_padding(substr, mod_mp.len - sig_mp.len, 0);
|
|
|
|
put_data(substr, sig_mp.ptr, sig_mp.len);
|
|
|
|
put_stringsb(pkt, substr);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Otherwise fall through and do it the easy way. We also come
|
|
|
|
* here as a fallback if we discover above that the key blob
|
|
|
|
* is misformatted in some way. */
|
|
|
|
give_up:;
|
|
|
|
}
|
|
|
|
|
|
|
|
put_stringpl(pkt, sigblob);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifndef NO_GSSAPI
|
|
|
|
static PktOut *ssh2_userauth_gss_packet(
|
|
|
|
struct ssh2_userauth_state *s, const char *authtype)
|
|
|
|
{
|
|
|
|
strbuf *sb;
|
|
|
|
PktOut *p;
|
|
|
|
Ssh_gss_buf buf;
|
|
|
|
Ssh_gss_buf mic;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The mic is computed over the session id + intended
|
|
|
|
* USERAUTH_REQUEST packet.
|
|
|
|
*/
|
|
|
|
sb = strbuf_new();
|
|
|
|
put_stringpl(sb, s->session_id);
|
|
|
|
put_byte(sb, SSH2_MSG_USERAUTH_REQUEST);
|
|
|
|
put_stringz(sb, s->username);
|
2018-10-09 17:11:17 +00:00
|
|
|
put_stringz(sb, s->successor_layer->vt->name);
|
Move most of ssh.c out into separate source files.
I've tried to separate out as many individually coherent changes from
this work as I could into their own commits, but here's where I run
out and have to commit the rest of this major refactoring as a
big-bang change.
Most of ssh.c is now no longer in ssh.c: all five of the main
coroutines that handle layers of the SSH-1 and SSH-2 protocols now
each have their own source file to live in, and a lot of the
supporting functions have moved into the appropriate one of those too.
The new abstraction is a vtable called 'PacketProtocolLayer', which
has an input and output packet queue. Each layer's main coroutine is
invoked from the method ssh_ppl_process_queue(), which is usually
(though not exclusively) triggered automatically when things are
pushed on the input queue. In SSH-2, the base layer is the transport
protocol, and it contains a pair of subsidiary queues by which it
passes some of its packets to the higher SSH-2 layers - first userauth
and then connection, which are peers at the same level, with the
former abdicating in favour of the latter at the appropriate moment.
SSH-1 is simpler: the whole login phase of the protocol (crypto setup
and authentication) is all in one module, and since SSH-1 has no
repeat key exchange, that setup layer abdicates in favour of the
connection phase when it's done.
ssh.c itself is now about a tenth of its old size (which all by itself
is cause for celebration!). Its main job is to set up all the layers,
hook them up to each other and to the BPP, and to funnel data back and
forth between that collection of modules and external things such as
the network and the terminal. Once it's set up a collection of packet
protocol layers, it communicates with them partly by calling methods
of the base layer (and if that's ssh2transport then it will delegate
some functionality to the corresponding methods of its higher layer),
and partly by talking directly to the connection layer no matter where
it is in the stack by means of the separate ConnectionLayer vtable
which I introduced in commit 8001dd4cb, and to which I've now added
quite a few extra methods replacing services that used to be internal
function calls within ssh.c.
(One effect of this is that the SSH-1 and SSH-2 channel storage is now
no longer shared - there are distinct struct types ssh1_channel and
ssh2_channel. That means a bit more code duplication, but on the plus
side, a lot fewer confusing conditionals in the middle of half-shared
functions, and less risk of a piece of SSH-1 escaping into SSH-2 or
vice versa, which I remember has happened at least once in the past.)
The bulk of this commit introduces the five new source files, their
common header sshppl.h and some shared supporting routines in
sshcommon.c, and rewrites nearly all of ssh.c itself. But it also
includes a couple of other changes that I couldn't separate easily
enough:
Firstly, there's a new handling for socket EOF, in which ssh.c sets an
'input_eof' flag in the BPP, and that responds by checking a flag that
tells it whether to report the EOF as an error or not. (This is the
main reason for those new BPP_READ / BPP_WAITFOR macros - they can
check the EOF flag every time the coroutine is resumed.)
Secondly, the error reporting itself is changed around again. I'd
expected to put some data fields in the public PacketProtocolLayer
structure that it could set to report errors in the same way as the
BPPs have been doing, but in the end, I decided propagating all those
data fields around was a pain and that even the BPPs shouldn't have
been doing it that way. So I've reverted to a system where everything
calls back to functions in ssh.c itself to report any connection-
ending condition. But there's a new family of those functions,
categorising the possible such conditions by semantics, and each one
has a different set of detailed effects (e.g. how rudely to close the
network connection, what exit status should be passed back to the
whole application, whether to send a disconnect message and/or display
a GUI error box).
I don't expect this to be immediately perfect: of course, the code has
been through a big upheaval, new bugs are expected, and I haven't been
able to do a full job of testing (e.g. I haven't tested every auth or
kex method). But I've checked that it _basically_ works - both SSH
protocols, all the different kinds of forwarding channel, more than
one auth method, Windows and Linux, connection sharing - and I think
it's now at the point where the easiest way to find further bugs is to
let it out into the wild and see what users can spot.
2018-09-24 17:28:16 +00:00
|
|
|
put_stringz(sb, authtype);
|
|
|
|
|
|
|
|
/* Compute the mic */
|
|
|
|
buf.value = sb->s;
|
|
|
|
buf.length = sb->len;
|
|
|
|
s->shgss->lib->get_mic(s->shgss->lib, s->shgss->ctx, &buf, &mic);
|
|
|
|
strbuf_free(sb);
|
|
|
|
|
|
|
|
/* Now we can build the real packet */
|
|
|
|
if (strcmp(authtype, "gssapi-with-mic") == 0) {
|
|
|
|
p = ssh_bpp_new_pktout(s->ppl.bpp, SSH2_MSG_USERAUTH_GSSAPI_MIC);
|
|
|
|
} else {
|
|
|
|
p = ssh_bpp_new_pktout(s->ppl.bpp, SSH2_MSG_USERAUTH_REQUEST);
|
|
|
|
put_stringz(p, s->username);
|
2018-10-09 17:11:17 +00:00
|
|
|
put_stringz(p, s->successor_layer->vt->name);
|
Move most of ssh.c out into separate source files.
I've tried to separate out as many individually coherent changes from
this work as I could into their own commits, but here's where I run
out and have to commit the rest of this major refactoring as a
big-bang change.
Most of ssh.c is now no longer in ssh.c: all five of the main
coroutines that handle layers of the SSH-1 and SSH-2 protocols now
each have their own source file to live in, and a lot of the
supporting functions have moved into the appropriate one of those too.
The new abstraction is a vtable called 'PacketProtocolLayer', which
has an input and output packet queue. Each layer's main coroutine is
invoked from the method ssh_ppl_process_queue(), which is usually
(though not exclusively) triggered automatically when things are
pushed on the input queue. In SSH-2, the base layer is the transport
protocol, and it contains a pair of subsidiary queues by which it
passes some of its packets to the higher SSH-2 layers - first userauth
and then connection, which are peers at the same level, with the
former abdicating in favour of the latter at the appropriate moment.
SSH-1 is simpler: the whole login phase of the protocol (crypto setup
and authentication) is all in one module, and since SSH-1 has no
repeat key exchange, that setup layer abdicates in favour of the
connection phase when it's done.
ssh.c itself is now about a tenth of its old size (which all by itself
is cause for celebration!). Its main job is to set up all the layers,
hook them up to each other and to the BPP, and to funnel data back and
forth between that collection of modules and external things such as
the network and the terminal. Once it's set up a collection of packet
protocol layers, it communicates with them partly by calling methods
of the base layer (and if that's ssh2transport then it will delegate
some functionality to the corresponding methods of its higher layer),
and partly by talking directly to the connection layer no matter where
it is in the stack by means of the separate ConnectionLayer vtable
which I introduced in commit 8001dd4cb, and to which I've now added
quite a few extra methods replacing services that used to be internal
function calls within ssh.c.
(One effect of this is that the SSH-1 and SSH-2 channel storage is now
no longer shared - there are distinct struct types ssh1_channel and
ssh2_channel. That means a bit more code duplication, but on the plus
side, a lot fewer confusing conditionals in the middle of half-shared
functions, and less risk of a piece of SSH-1 escaping into SSH-2 or
vice versa, which I remember has happened at least once in the past.)
The bulk of this commit introduces the five new source files, their
common header sshppl.h and some shared supporting routines in
sshcommon.c, and rewrites nearly all of ssh.c itself. But it also
includes a couple of other changes that I couldn't separate easily
enough:
Firstly, there's a new handling for socket EOF, in which ssh.c sets an
'input_eof' flag in the BPP, and that responds by checking a flag that
tells it whether to report the EOF as an error or not. (This is the
main reason for those new BPP_READ / BPP_WAITFOR macros - they can
check the EOF flag every time the coroutine is resumed.)
Secondly, the error reporting itself is changed around again. I'd
expected to put some data fields in the public PacketProtocolLayer
structure that it could set to report errors in the same way as the
BPPs have been doing, but in the end, I decided propagating all those
data fields around was a pain and that even the BPPs shouldn't have
been doing it that way. So I've reverted to a system where everything
calls back to functions in ssh.c itself to report any connection-
ending condition. But there's a new family of those functions,
categorising the possible such conditions by semantics, and each one
has a different set of detailed effects (e.g. how rudely to close the
network connection, what exit status should be passed back to the
whole application, whether to send a disconnect message and/or display
a GUI error box).
I don't expect this to be immediately perfect: of course, the code has
been through a big upheaval, new bugs are expected, and I haven't been
able to do a full job of testing (e.g. I haven't tested every auth or
kex method). But I've checked that it _basically_ works - both SSH
protocols, all the different kinds of forwarding channel, more than
one auth method, Windows and Linux, connection sharing - and I think
it's now at the point where the easiest way to find further bugs is to
let it out into the wild and see what users can spot.
2018-09-24 17:28:16 +00:00
|
|
|
put_stringz(p, authtype);
|
|
|
|
}
|
|
|
|
put_string(p, mic.value, mic.length);
|
|
|
|
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static int ssh2_userauth_get_specials(
|
|
|
|
PacketProtocolLayer *ppl, add_special_fn_t add_special, void *ctx)
|
|
|
|
{
|
|
|
|
/* No specials provided by this layer. */
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void ssh2_userauth_special_cmd(PacketProtocolLayer *ppl,
|
|
|
|
SessionSpecialCode code, int arg)
|
|
|
|
{
|
|
|
|
/* No specials provided by this layer. */
|
|
|
|
}
|
|
|
|
|
|
|
|
static int ssh2_userauth_want_user_input(PacketProtocolLayer *ppl)
|
|
|
|
{
|
|
|
|
struct ssh2_userauth_state *s =
|
2018-10-05 22:49:08 +00:00
|
|
|
container_of(ppl, struct ssh2_userauth_state, ppl);
|
Move most of ssh.c out into separate source files.
I've tried to separate out as many individually coherent changes from
this work as I could into their own commits, but here's where I run
out and have to commit the rest of this major refactoring as a
big-bang change.
Most of ssh.c is now no longer in ssh.c: all five of the main
coroutines that handle layers of the SSH-1 and SSH-2 protocols now
each have their own source file to live in, and a lot of the
supporting functions have moved into the appropriate one of those too.
The new abstraction is a vtable called 'PacketProtocolLayer', which
has an input and output packet queue. Each layer's main coroutine is
invoked from the method ssh_ppl_process_queue(), which is usually
(though not exclusively) triggered automatically when things are
pushed on the input queue. In SSH-2, the base layer is the transport
protocol, and it contains a pair of subsidiary queues by which it
passes some of its packets to the higher SSH-2 layers - first userauth
and then connection, which are peers at the same level, with the
former abdicating in favour of the latter at the appropriate moment.
SSH-1 is simpler: the whole login phase of the protocol (crypto setup
and authentication) is all in one module, and since SSH-1 has no
repeat key exchange, that setup layer abdicates in favour of the
connection phase when it's done.
ssh.c itself is now about a tenth of its old size (which all by itself
is cause for celebration!). Its main job is to set up all the layers,
hook them up to each other and to the BPP, and to funnel data back and
forth between that collection of modules and external things such as
the network and the terminal. Once it's set up a collection of packet
protocol layers, it communicates with them partly by calling methods
of the base layer (and if that's ssh2transport then it will delegate
some functionality to the corresponding methods of its higher layer),
and partly by talking directly to the connection layer no matter where
it is in the stack by means of the separate ConnectionLayer vtable
which I introduced in commit 8001dd4cb, and to which I've now added
quite a few extra methods replacing services that used to be internal
function calls within ssh.c.
(One effect of this is that the SSH-1 and SSH-2 channel storage is now
no longer shared - there are distinct struct types ssh1_channel and
ssh2_channel. That means a bit more code duplication, but on the plus
side, a lot fewer confusing conditionals in the middle of half-shared
functions, and less risk of a piece of SSH-1 escaping into SSH-2 or
vice versa, which I remember has happened at least once in the past.)
The bulk of this commit introduces the five new source files, their
common header sshppl.h and some shared supporting routines in
sshcommon.c, and rewrites nearly all of ssh.c itself. But it also
includes a couple of other changes that I couldn't separate easily
enough:
Firstly, there's a new handling for socket EOF, in which ssh.c sets an
'input_eof' flag in the BPP, and that responds by checking a flag that
tells it whether to report the EOF as an error or not. (This is the
main reason for those new BPP_READ / BPP_WAITFOR macros - they can
check the EOF flag every time the coroutine is resumed.)
Secondly, the error reporting itself is changed around again. I'd
expected to put some data fields in the public PacketProtocolLayer
structure that it could set to report errors in the same way as the
BPPs have been doing, but in the end, I decided propagating all those
data fields around was a pain and that even the BPPs shouldn't have
been doing it that way. So I've reverted to a system where everything
calls back to functions in ssh.c itself to report any connection-
ending condition. But there's a new family of those functions,
categorising the possible such conditions by semantics, and each one
has a different set of detailed effects (e.g. how rudely to close the
network connection, what exit status should be passed back to the
whole application, whether to send a disconnect message and/or display
a GUI error box).
I don't expect this to be immediately perfect: of course, the code has
been through a big upheaval, new bugs are expected, and I haven't been
able to do a full job of testing (e.g. I haven't tested every auth or
kex method). But I've checked that it _basically_ works - both SSH
protocols, all the different kinds of forwarding channel, more than
one auth method, Windows and Linux, connection sharing - and I think
it's now at the point where the easiest way to find further bugs is to
let it out into the wild and see what users can spot.
2018-09-24 17:28:16 +00:00
|
|
|
return s->want_user_input;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void ssh2_userauth_got_user_input(PacketProtocolLayer *ppl)
|
|
|
|
{
|
|
|
|
struct ssh2_userauth_state *s =
|
2018-10-05 22:49:08 +00:00
|
|
|
container_of(ppl, struct ssh2_userauth_state, ppl);
|
Move most of ssh.c out into separate source files.
I've tried to separate out as many individually coherent changes from
this work as I could into their own commits, but here's where I run
out and have to commit the rest of this major refactoring as a
big-bang change.
Most of ssh.c is now no longer in ssh.c: all five of the main
coroutines that handle layers of the SSH-1 and SSH-2 protocols now
each have their own source file to live in, and a lot of the
supporting functions have moved into the appropriate one of those too.
The new abstraction is a vtable called 'PacketProtocolLayer', which
has an input and output packet queue. Each layer's main coroutine is
invoked from the method ssh_ppl_process_queue(), which is usually
(though not exclusively) triggered automatically when things are
pushed on the input queue. In SSH-2, the base layer is the transport
protocol, and it contains a pair of subsidiary queues by which it
passes some of its packets to the higher SSH-2 layers - first userauth
and then connection, which are peers at the same level, with the
former abdicating in favour of the latter at the appropriate moment.
SSH-1 is simpler: the whole login phase of the protocol (crypto setup
and authentication) is all in one module, and since SSH-1 has no
repeat key exchange, that setup layer abdicates in favour of the
connection phase when it's done.
ssh.c itself is now about a tenth of its old size (which all by itself
is cause for celebration!). Its main job is to set up all the layers,
hook them up to each other and to the BPP, and to funnel data back and
forth between that collection of modules and external things such as
the network and the terminal. Once it's set up a collection of packet
protocol layers, it communicates with them partly by calling methods
of the base layer (and if that's ssh2transport then it will delegate
some functionality to the corresponding methods of its higher layer),
and partly by talking directly to the connection layer no matter where
it is in the stack by means of the separate ConnectionLayer vtable
which I introduced in commit 8001dd4cb, and to which I've now added
quite a few extra methods replacing services that used to be internal
function calls within ssh.c.
(One effect of this is that the SSH-1 and SSH-2 channel storage is now
no longer shared - there are distinct struct types ssh1_channel and
ssh2_channel. That means a bit more code duplication, but on the plus
side, a lot fewer confusing conditionals in the middle of half-shared
functions, and less risk of a piece of SSH-1 escaping into SSH-2 or
vice versa, which I remember has happened at least once in the past.)
The bulk of this commit introduces the five new source files, their
common header sshppl.h and some shared supporting routines in
sshcommon.c, and rewrites nearly all of ssh.c itself. But it also
includes a couple of other changes that I couldn't separate easily
enough:
Firstly, there's a new handling for socket EOF, in which ssh.c sets an
'input_eof' flag in the BPP, and that responds by checking a flag that
tells it whether to report the EOF as an error or not. (This is the
main reason for those new BPP_READ / BPP_WAITFOR macros - they can
check the EOF flag every time the coroutine is resumed.)
Secondly, the error reporting itself is changed around again. I'd
expected to put some data fields in the public PacketProtocolLayer
structure that it could set to report errors in the same way as the
BPPs have been doing, but in the end, I decided propagating all those
data fields around was a pain and that even the BPPs shouldn't have
been doing it that way. So I've reverted to a system where everything
calls back to functions in ssh.c itself to report any connection-
ending condition. But there's a new family of those functions,
categorising the possible such conditions by semantics, and each one
has a different set of detailed effects (e.g. how rudely to close the
network connection, what exit status should be passed back to the
whole application, whether to send a disconnect message and/or display
a GUI error box).
I don't expect this to be immediately perfect: of course, the code has
been through a big upheaval, new bugs are expected, and I haven't been
able to do a full job of testing (e.g. I haven't tested every auth or
kex method). But I've checked that it _basically_ works - both SSH
protocols, all the different kinds of forwarding channel, more than
one auth method, Windows and Linux, connection sharing - and I think
it's now at the point where the easiest way to find further bugs is to
let it out into the wild and see what users can spot.
2018-09-24 17:28:16 +00:00
|
|
|
if (s->want_user_input)
|
|
|
|
queue_idempotent_callback(&s->ppl.ic_process_queue);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void ssh2_userauth_reconfigure(PacketProtocolLayer *ppl, Conf *conf)
|
|
|
|
{
|
|
|
|
struct ssh2_userauth_state *s =
|
2018-10-05 22:49:08 +00:00
|
|
|
container_of(ppl, struct ssh2_userauth_state, ppl);
|
Move most of ssh.c out into separate source files.
I've tried to separate out as many individually coherent changes from
this work as I could into their own commits, but here's where I run
out and have to commit the rest of this major refactoring as a
big-bang change.
Most of ssh.c is now no longer in ssh.c: all five of the main
coroutines that handle layers of the SSH-1 and SSH-2 protocols now
each have their own source file to live in, and a lot of the
supporting functions have moved into the appropriate one of those too.
The new abstraction is a vtable called 'PacketProtocolLayer', which
has an input and output packet queue. Each layer's main coroutine is
invoked from the method ssh_ppl_process_queue(), which is usually
(though not exclusively) triggered automatically when things are
pushed on the input queue. In SSH-2, the base layer is the transport
protocol, and it contains a pair of subsidiary queues by which it
passes some of its packets to the higher SSH-2 layers - first userauth
and then connection, which are peers at the same level, with the
former abdicating in favour of the latter at the appropriate moment.
SSH-1 is simpler: the whole login phase of the protocol (crypto setup
and authentication) is all in one module, and since SSH-1 has no
repeat key exchange, that setup layer abdicates in favour of the
connection phase when it's done.
ssh.c itself is now about a tenth of its old size (which all by itself
is cause for celebration!). Its main job is to set up all the layers,
hook them up to each other and to the BPP, and to funnel data back and
forth between that collection of modules and external things such as
the network and the terminal. Once it's set up a collection of packet
protocol layers, it communicates with them partly by calling methods
of the base layer (and if that's ssh2transport then it will delegate
some functionality to the corresponding methods of its higher layer),
and partly by talking directly to the connection layer no matter where
it is in the stack by means of the separate ConnectionLayer vtable
which I introduced in commit 8001dd4cb, and to which I've now added
quite a few extra methods replacing services that used to be internal
function calls within ssh.c.
(One effect of this is that the SSH-1 and SSH-2 channel storage is now
no longer shared - there are distinct struct types ssh1_channel and
ssh2_channel. That means a bit more code duplication, but on the plus
side, a lot fewer confusing conditionals in the middle of half-shared
functions, and less risk of a piece of SSH-1 escaping into SSH-2 or
vice versa, which I remember has happened at least once in the past.)
The bulk of this commit introduces the five new source files, their
common header sshppl.h and some shared supporting routines in
sshcommon.c, and rewrites nearly all of ssh.c itself. But it also
includes a couple of other changes that I couldn't separate easily
enough:
Firstly, there's a new handling for socket EOF, in which ssh.c sets an
'input_eof' flag in the BPP, and that responds by checking a flag that
tells it whether to report the EOF as an error or not. (This is the
main reason for those new BPP_READ / BPP_WAITFOR macros - they can
check the EOF flag every time the coroutine is resumed.)
Secondly, the error reporting itself is changed around again. I'd
expected to put some data fields in the public PacketProtocolLayer
structure that it could set to report errors in the same way as the
BPPs have been doing, but in the end, I decided propagating all those
data fields around was a pain and that even the BPPs shouldn't have
been doing it that way. So I've reverted to a system where everything
calls back to functions in ssh.c itself to report any connection-
ending condition. But there's a new family of those functions,
categorising the possible such conditions by semantics, and each one
has a different set of detailed effects (e.g. how rudely to close the
network connection, what exit status should be passed back to the
whole application, whether to send a disconnect message and/or display
a GUI error box).
I don't expect this to be immediately perfect: of course, the code has
been through a big upheaval, new bugs are expected, and I haven't been
able to do a full job of testing (e.g. I haven't tested every auth or
kex method). But I've checked that it _basically_ works - both SSH
protocols, all the different kinds of forwarding channel, more than
one auth method, Windows and Linux, connection sharing - and I think
it's now at the point where the easiest way to find further bugs is to
let it out into the wild and see what users can spot.
2018-09-24 17:28:16 +00:00
|
|
|
ssh_ppl_reconfigure(s->successor_layer, conf);
|
|
|
|
}
|