1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-01-09 17:38:00 +00:00
putty-source/ssh1connection-client.c

532 lines
16 KiB
C
Raw Normal View History

Move client-specific SSH code into new files. This is a major code reorganisation in preparation for making this code base into one that can build an SSH server as well as a client. (Mostly for purposes of using the server as a regression test suite for the client, though I have some other possible uses in mind too. However, it's currently no part of my plan to harden the server to the point where it can sensibly be deployed in a hostile environment.) In this preparatory commit, I've broken up the SSH-2 transport and connection layers, and the SSH-1 connection layer, into multiple source files, with each layer having its own header file containing the shared type definitions. In each case, the new source file contains code that's specific to the client side of the protocol, so that a new file can be swapped in in its place when building the server. Mostly this is just a straightforward moving of code without changing it very much, but there are a couple of actual changes in the process: The parsing of SSH-2 global-request and channel open-messages is now done by a new pair of functions in the client module. For channel opens, I've invented a new union data type to be the return value from that function, representing either failure (plus error message), success (plus Channel instance to manage the new channel), or an instruction to hand the channel over to a sharing downstream (plus a pointer to the downstream in question). Also, the tree234 of remote port forwardings in ssh2connection is now initialised on first use by the client-specific code, so that's where its compare function lives. The shared ssh2connection_free() still takes responsibility for freeing it, but now has to check if it's non-null first. The outer shell of the ssh2_lportfwd_open method, for making a local-to-remote port forwarding, is still centralised in ssh2connection.c, but the part of it that actually constructs the outgoing channel-open message has moved into the client code, because that will have to change depending on whether the channel-open has to have type direct-tcpip or forwarded-tcpip. In the SSH-1 connection layer, half the filter_queue method has moved out into the new client-specific code, but not all of it - bidirectional channel maintenance messages are still handled centrally. One exception is SSH_MSG_PORT_OPEN, which can be sent in both directions, but with subtly different semantics - from server to client, it's referring to a previously established remote forwarding (and must be rejected if there isn't one that matches it), but from client to server it's just a "direct-tcpip" request with no prior context. So that one is in the client-specific module, and when I add the server code it will have its own different handler.
2018-10-20 16:57:37 +00:00
/*
* Client-specific parts of the SSH-1 connection layer.
*/
#include <assert.h>
#include "putty.h"
#include "ssh.h"
#include "sshbpp.h"
#include "sshppl.h"
#include "sshchan.h"
#include "sshcr.h"
#include "ssh1connection.h"
void ssh1_connection_direction_specific_setup(
struct ssh1_connection_state *s)
{
if (!s->mainchan) {
/*
* Start up the main session, by telling mainchan.c to do it
* all just as it would in SSH-2, and translating those
* concepts to SSH-1's non-channel-shaped idea of the main
* session.
*/
s->mainchan = mainchan_new(
&s->ppl, &s->cl, s->conf, s->term_width, s->term_height,
FALSE /* is_simple */, NULL);
}
}
typedef void (*sf_handler_fn_t)(struct ssh1_connection_state *s,
int success, void *ctx);
struct outstanding_succfail {
sf_handler_fn_t handler;
void *ctx;
struct outstanding_succfail *next;
/*
* The 'trivial' flag is set if this handler is in response to a
* request for which the SSH-1 protocol doesn't actually specify a
* response packet. The client of this system (mainchan.c) will
* expect to get an acknowledgment regardless, so we arrange to
* send that ack immediately after the rest of the queue empties.
*/
int trivial;
};
static void ssh1_connection_process_trivial_succfails(void *vs);
static void ssh1_queue_succfail_handler(
struct ssh1_connection_state *s, sf_handler_fn_t handler, void *ctx,
int trivial)
{
struct outstanding_succfail *osf = snew(struct outstanding_succfail);
osf->handler = handler;
osf->ctx = ctx;
osf->trivial = trivial;
osf->next = NULL;
if (s->succfail_tail)
s->succfail_tail->next = osf;
else
s->succfail_head = osf;
s->succfail_tail = osf;
/* In case this one was trivial and the queue was already empty,
* we should make sure we run the handler promptly, and the
* easiest way is to queue it anyway and then run a trivials pass
* by callback. */
queue_toplevel_callback(ssh1_connection_process_trivial_succfails, s);
}
static void ssh1_connection_process_succfail(
struct ssh1_connection_state *s, int success)
{
struct outstanding_succfail *prevhead = s->succfail_head;
s->succfail_head = s->succfail_head->next;
if (!s->succfail_head)
s->succfail_tail = NULL;
prevhead->handler(s, success, prevhead->ctx);
sfree(prevhead);
}
static void ssh1_connection_process_trivial_succfails(void *vs)
{
struct ssh1_connection_state *s = (struct ssh1_connection_state *)vs;
while (s->succfail_head && s->succfail_head->trivial)
ssh1_connection_process_succfail(s, TRUE);
}
int ssh1_handle_direction_specific_packet(
struct ssh1_connection_state *s, PktIn *pktin)
{
PacketProtocolLayer *ppl = &s->ppl; /* for ppl_logevent */
PktOut *pktout;
struct ssh1_channel *c;
unsigned remid;
struct ssh_rportfwd pf, *pfp;
ptrlen host, data;
int port;
switch (pktin->type) {
case SSH1_SMSG_SUCCESS:
case SSH1_SMSG_FAILURE:
if (!s->succfail_head) {
ssh_remote_error(s->ppl.ssh,
"Received %s with no outstanding request",
ssh1_pkt_type(pktin->type));
return TRUE;
}
ssh1_connection_process_succfail(
s, pktin->type == SSH1_SMSG_SUCCESS);
queue_toplevel_callback(
ssh1_connection_process_trivial_succfails, s);
return TRUE;
case SSH1_SMSG_X11_OPEN:
remid = get_uint32(pktin);
/* Refuse if X11 forwarding is disabled. */
if (!s->X11_fwd_enabled) {
pktout = ssh_bpp_new_pktout(
s->ppl.bpp, SSH1_MSG_CHANNEL_OPEN_FAILURE);
put_uint32(pktout, remid);
pq_push(s->ppl.out_pq, pktout);
ppl_logevent(("Rejected X11 connect request"));
} else {
c = snew(struct ssh1_channel);
c->connlayer = s;
ssh1_channel_init(c);
c->remoteid = remid;
c->chan = x11_new_channel(s->x11authtree, &c->sc,
NULL, -1, FALSE);
c->remoteid = remid;
c->halfopen = FALSE;
pktout = ssh_bpp_new_pktout(
s->ppl.bpp, SSH1_MSG_CHANNEL_OPEN_CONFIRMATION);
put_uint32(pktout, c->remoteid);
put_uint32(pktout, c->localid);
pq_push(s->ppl.out_pq, pktout);
ppl_logevent(("Opened X11 forward channel"));
}
return TRUE;
case SSH1_SMSG_AGENT_OPEN:
remid = get_uint32(pktin);
/* Refuse if agent forwarding is disabled. */
if (!s->agent_fwd_enabled) {
pktout = ssh_bpp_new_pktout(
s->ppl.bpp, SSH1_MSG_CHANNEL_OPEN_FAILURE);
put_uint32(pktout, remid);
pq_push(s->ppl.out_pq, pktout);
} else {
c = snew(struct ssh1_channel);
c->connlayer = s;
ssh1_channel_init(c);
c->remoteid = remid;
c->chan = agentf_new(&c->sc);
c->halfopen = FALSE;
pktout = ssh_bpp_new_pktout(
s->ppl.bpp, SSH1_MSG_CHANNEL_OPEN_CONFIRMATION);
put_uint32(pktout, c->remoteid);
put_uint32(pktout, c->localid);
pq_push(s->ppl.out_pq, pktout);
}
return TRUE;
case SSH1_MSG_PORT_OPEN:
remid = get_uint32(pktin);
host = get_string(pktin);
port = toint(get_uint32(pktin));
pf.dhost = mkstr(host);
pf.dport = port;
pfp = find234(s->rportfwds, &pf, NULL);
if (!pfp) {
ppl_logevent(("Rejected remote port open request for %s:%d",
pf.dhost, port));
pktout = ssh_bpp_new_pktout(
s->ppl.bpp, SSH1_MSG_CHANNEL_OPEN_FAILURE);
put_uint32(pktout, remid);
pq_push(s->ppl.out_pq, pktout);
} else {
char *err;
c = snew(struct ssh1_channel);
c->connlayer = s;
ppl_logevent(("Received remote port open request for %s:%d",
pf.dhost, port));
err = portfwdmgr_connect(
s->portfwdmgr, &c->chan, pf.dhost, port,
&c->sc, pfp->addressfamily);
if (err) {
ppl_logevent(("Port open failed: %s", err));
sfree(err);
ssh1_channel_free(c);
pktout = ssh_bpp_new_pktout(
s->ppl.bpp, SSH1_MSG_CHANNEL_OPEN_FAILURE);
put_uint32(pktout, remid);
pq_push(s->ppl.out_pq, pktout);
} else {
ssh1_channel_init(c);
c->remoteid = remid;
c->halfopen = FALSE;
pktout = ssh_bpp_new_pktout(
s->ppl.bpp, SSH1_MSG_CHANNEL_OPEN_CONFIRMATION);
put_uint32(pktout, c->remoteid);
put_uint32(pktout, c->localid);
pq_push(s->ppl.out_pq, pktout);
ppl_logevent(("Forwarded port opened successfully"));
}
}
sfree(pf.dhost);
return TRUE;
case SSH1_SMSG_STDOUT_DATA:
case SSH1_SMSG_STDERR_DATA:
data = get_string(pktin);
if (!get_err(pktin)) {
int bufsize = seat_output(
s->ppl.seat, pktin->type == SSH1_SMSG_STDERR_DATA,
data.ptr, data.len);
if (!s->stdout_throttling && bufsize > SSH1_BUFFER_LIMIT) {
s->stdout_throttling = 1;
ssh_throttle_conn(s->ppl.ssh, +1);
}
}
return TRUE;
case SSH1_SMSG_EXIT_STATUS:
{
int exitcode = get_uint32(pktin);
ppl_logevent(("Server sent command exit status %d", exitcode));
ssh_got_exitcode(s->ppl.ssh, exitcode);
s->session_terminated = TRUE;
}
return TRUE;
default:
return FALSE;
}
}
static void ssh1mainchan_succfail_wantreply(struct ssh1_connection_state *s,
int success, void *ctx)
{
chan_request_response(s->mainchan_chan, success);
}
static void ssh1mainchan_succfail_nowantreply(struct ssh1_connection_state *s,
int success, void *ctx)
{
}
static void ssh1mainchan_queue_response(struct ssh1_connection_state *s,
int want_reply, int trivial)
{
sf_handler_fn_t handler = (want_reply ? ssh1mainchan_succfail_wantreply :
ssh1mainchan_succfail_nowantreply);
ssh1_queue_succfail_handler(s, handler, NULL, trivial);
}
static void ssh1mainchan_request_x11_forwarding(
SshChannel *sc, int want_reply, const char *authproto,
const char *authdata, int screen_number, int oneshot)
{
struct ssh1_connection_state *s =
container_of(sc, struct ssh1_connection_state, mainchan_sc);
PktOut *pktout;
pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_CMSG_X11_REQUEST_FORWARDING);
put_stringz(pktout, authproto);
put_stringz(pktout, authdata);
if (s->local_protoflags & SSH1_PROTOFLAG_SCREEN_NUMBER)
put_uint32(pktout, screen_number);
pq_push(s->ppl.out_pq, pktout);
ssh1mainchan_queue_response(s, want_reply, FALSE);
}
static void ssh1mainchan_request_agent_forwarding(
SshChannel *sc, int want_reply)
{
struct ssh1_connection_state *s =
container_of(sc, struct ssh1_connection_state, mainchan_sc);
PktOut *pktout;
pktout = ssh_bpp_new_pktout(
s->ppl.bpp, SSH1_CMSG_AGENT_REQUEST_FORWARDING);
pq_push(s->ppl.out_pq, pktout);
ssh1mainchan_queue_response(s, want_reply, FALSE);
}
static void ssh1mainchan_request_pty(
SshChannel *sc, int want_reply, Conf *conf, int w, int h)
{
struct ssh1_connection_state *s =
container_of(sc, struct ssh1_connection_state, mainchan_sc);
PktOut *pktout;
pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_CMSG_REQUEST_PTY);
put_stringz(pktout, conf_get_str(s->conf, CONF_termtype));
put_uint32(pktout, h);
put_uint32(pktout, w);
put_uint32(pktout, 0); /* width in pixels */
put_uint32(pktout, 0); /* height in pixels */
write_ttymodes_to_packet(
BinarySink_UPCAST(pktout), 1,
get_ttymodes_from_conf(s->ppl.seat, conf));
pq_push(s->ppl.out_pq, pktout);
ssh1mainchan_queue_response(s, want_reply, FALSE);
}
static int ssh1mainchan_send_env_var(
SshChannel *sc, int want_reply, const char *var, const char *value)
{
return FALSE; /* SSH-1 doesn't support this at all */
}
static void ssh1mainchan_start_shell(
SshChannel *sc, int want_reply)
{
struct ssh1_connection_state *s =
container_of(sc, struct ssh1_connection_state, mainchan_sc);
PktOut *pktout;
pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_CMSG_EXEC_SHELL);
pq_push(s->ppl.out_pq, pktout);
ssh1mainchan_queue_response(s, want_reply, TRUE);
}
static void ssh1mainchan_start_command(
SshChannel *sc, int want_reply, const char *command)
{
struct ssh1_connection_state *s =
container_of(sc, struct ssh1_connection_state, mainchan_sc);
PktOut *pktout;
pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_CMSG_EXEC_CMD);
put_stringz(pktout, command);
pq_push(s->ppl.out_pq, pktout);
ssh1mainchan_queue_response(s, want_reply, TRUE);
}
static int ssh1mainchan_start_subsystem(
SshChannel *sc, int want_reply, const char *subsystem)
{
return FALSE; /* SSH-1 doesn't support this at all */
}
static int ssh1mainchan_send_serial_break(
SshChannel *sc, int want_reply, int length)
{
return FALSE; /* SSH-1 doesn't support this at all */
}
static int ssh1mainchan_send_signal(
SshChannel *sc, int want_reply, const char *signame)
{
return FALSE; /* SSH-1 doesn't support this at all */
}
static void ssh1mainchan_send_terminal_size_change(
SshChannel *sc, int w, int h)
{
struct ssh1_connection_state *s =
container_of(sc, struct ssh1_connection_state, mainchan_sc);
PktOut *pktout;
pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_CMSG_WINDOW_SIZE);
put_uint32(pktout, h);
put_uint32(pktout, w);
put_uint32(pktout, 0); /* width in pixels */
put_uint32(pktout, 0); /* height in pixels */
pq_push(s->ppl.out_pq, pktout);
}
static void ssh1mainchan_hint_channel_is_simple(SshChannel *sc)
{
}
static int ssh1mainchan_write(
SshChannel *sc, int is_stderr, const void *data, int len)
Move client-specific SSH code into new files. This is a major code reorganisation in preparation for making this code base into one that can build an SSH server as well as a client. (Mostly for purposes of using the server as a regression test suite for the client, though I have some other possible uses in mind too. However, it's currently no part of my plan to harden the server to the point where it can sensibly be deployed in a hostile environment.) In this preparatory commit, I've broken up the SSH-2 transport and connection layers, and the SSH-1 connection layer, into multiple source files, with each layer having its own header file containing the shared type definitions. In each case, the new source file contains code that's specific to the client side of the protocol, so that a new file can be swapped in in its place when building the server. Mostly this is just a straightforward moving of code without changing it very much, but there are a couple of actual changes in the process: The parsing of SSH-2 global-request and channel open-messages is now done by a new pair of functions in the client module. For channel opens, I've invented a new union data type to be the return value from that function, representing either failure (plus error message), success (plus Channel instance to manage the new channel), or an instruction to hand the channel over to a sharing downstream (plus a pointer to the downstream in question). Also, the tree234 of remote port forwardings in ssh2connection is now initialised on first use by the client-specific code, so that's where its compare function lives. The shared ssh2connection_free() still takes responsibility for freeing it, but now has to check if it's non-null first. The outer shell of the ssh2_lportfwd_open method, for making a local-to-remote port forwarding, is still centralised in ssh2connection.c, but the part of it that actually constructs the outgoing channel-open message has moved into the client code, because that will have to change depending on whether the channel-open has to have type direct-tcpip or forwarded-tcpip. In the SSH-1 connection layer, half the filter_queue method has moved out into the new client-specific code, but not all of it - bidirectional channel maintenance messages are still handled centrally. One exception is SSH_MSG_PORT_OPEN, which can be sent in both directions, but with subtly different semantics - from server to client, it's referring to a previously established remote forwarding (and must be rejected if there isn't one that matches it), but from client to server it's just a "direct-tcpip" request with no prior context. So that one is in the client-specific module, and when I add the server code it will have its own different handler.
2018-10-20 16:57:37 +00:00
{
struct ssh1_connection_state *s =
container_of(sc, struct ssh1_connection_state, mainchan_sc);
PktOut *pktout;
pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_CMSG_STDIN_DATA);
put_string(pktout, data, len);
pq_push(s->ppl.out_pq, pktout);
return 0;
}
static void ssh1mainchan_write_eof(SshChannel *sc)
{
struct ssh1_connection_state *s =
container_of(sc, struct ssh1_connection_state, mainchan_sc);
PktOut *pktout;
pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_CMSG_EOF);
pq_push(s->ppl.out_pq, pktout);
}
static const struct SshChannelVtable ssh1mainchan_vtable = {
ssh1mainchan_write,
ssh1mainchan_write_eof,
NULL /* unclean_close */,
NULL /* unthrottle */,
NULL /* get_conf */,
NULL /* window_override_removed is only used by SSH-2 sharing */,
NULL /* x11_sharing_handover, likewise */,
NULL /* send_exit_status */,
NULL /* send_exit_signal */,
NULL /* send_exit_signal_numeric */,
Move client-specific SSH code into new files. This is a major code reorganisation in preparation for making this code base into one that can build an SSH server as well as a client. (Mostly for purposes of using the server as a regression test suite for the client, though I have some other possible uses in mind too. However, it's currently no part of my plan to harden the server to the point where it can sensibly be deployed in a hostile environment.) In this preparatory commit, I've broken up the SSH-2 transport and connection layers, and the SSH-1 connection layer, into multiple source files, with each layer having its own header file containing the shared type definitions. In each case, the new source file contains code that's specific to the client side of the protocol, so that a new file can be swapped in in its place when building the server. Mostly this is just a straightforward moving of code without changing it very much, but there are a couple of actual changes in the process: The parsing of SSH-2 global-request and channel open-messages is now done by a new pair of functions in the client module. For channel opens, I've invented a new union data type to be the return value from that function, representing either failure (plus error message), success (plus Channel instance to manage the new channel), or an instruction to hand the channel over to a sharing downstream (plus a pointer to the downstream in question). Also, the tree234 of remote port forwardings in ssh2connection is now initialised on first use by the client-specific code, so that's where its compare function lives. The shared ssh2connection_free() still takes responsibility for freeing it, but now has to check if it's non-null first. The outer shell of the ssh2_lportfwd_open method, for making a local-to-remote port forwarding, is still centralised in ssh2connection.c, but the part of it that actually constructs the outgoing channel-open message has moved into the client code, because that will have to change depending on whether the channel-open has to have type direct-tcpip or forwarded-tcpip. In the SSH-1 connection layer, half the filter_queue method has moved out into the new client-specific code, but not all of it - bidirectional channel maintenance messages are still handled centrally. One exception is SSH_MSG_PORT_OPEN, which can be sent in both directions, but with subtly different semantics - from server to client, it's referring to a previously established remote forwarding (and must be rejected if there isn't one that matches it), but from client to server it's just a "direct-tcpip" request with no prior context. So that one is in the client-specific module, and when I add the server code it will have its own different handler.
2018-10-20 16:57:37 +00:00
ssh1mainchan_request_x11_forwarding,
ssh1mainchan_request_agent_forwarding,
ssh1mainchan_request_pty,
ssh1mainchan_send_env_var,
ssh1mainchan_start_shell,
ssh1mainchan_start_command,
ssh1mainchan_start_subsystem,
ssh1mainchan_send_serial_break,
ssh1mainchan_send_signal,
ssh1mainchan_send_terminal_size_change,
ssh1mainchan_hint_channel_is_simple,
};
static void ssh1_session_confirm_callback(void *vctx)
{
struct ssh1_connection_state *s = (struct ssh1_connection_state *)vctx;
chan_open_confirmation(s->mainchan_chan);
}
SshChannel *ssh1_session_open(ConnectionLayer *cl, Channel *chan)
{
struct ssh1_connection_state *s =
container_of(cl, struct ssh1_connection_state, cl);
s->mainchan_sc.vt = &ssh1mainchan_vtable;
s->mainchan_sc.cl = &s->cl;
s->mainchan_chan = chan;
queue_toplevel_callback(ssh1_session_confirm_callback, s);
return &s->mainchan_sc;
}
static void ssh1_rportfwd_response(struct ssh1_connection_state *s,
int success, void *ctx)
{
PacketProtocolLayer *ppl = &s->ppl; /* for ppl_logevent */
struct ssh_rportfwd *rpf = (struct ssh_rportfwd *)ctx;
if (success) {
ppl_logevent(("Remote port forwarding from %s enabled",
rpf->log_description));
} else {
ppl_logevent(("Remote port forwarding from %s refused",
rpf->log_description));
struct ssh_rportfwd *realpf = del234(s->rportfwds, rpf);
assert(realpf == rpf);
portfwdmgr_close(s->portfwdmgr, rpf->pfr);
free_rportfwd(rpf);
}
}
struct ssh_rportfwd *ssh1_rportfwd_alloc(
ConnectionLayer *cl,
const char *shost, int sport, const char *dhost, int dport,
int addressfamily, const char *log_description, PortFwdRecord *pfr,
ssh_sharing_connstate *share_ctx)
{
struct ssh1_connection_state *s =
container_of(cl, struct ssh1_connection_state, cl);
struct ssh_rportfwd *rpf = snew(struct ssh_rportfwd);
rpf->shost = dupstr(shost);
rpf->sport = sport;
rpf->dhost = dupstr(dhost);
rpf->dport = dport;
rpf->addressfamily = addressfamily;
rpf->log_description = dupstr(log_description);
rpf->pfr = pfr;
if (add234(s->rportfwds, rpf) != rpf) {
free_rportfwd(rpf);
return NULL;
}
PktOut *pktout = ssh_bpp_new_pktout(
s->ppl.bpp, SSH1_CMSG_PORT_FORWARD_REQUEST);
put_uint32(pktout, rpf->sport);
put_stringz(pktout, rpf->dhost);
put_uint32(pktout, rpf->dport);
pq_push(s->ppl.out_pq, pktout);
ssh1_queue_succfail_handler(s, ssh1_rportfwd_response, rpf, FALSE);
return rpf;
}
Add an actual SSH server program. This server is NOT SECURE! If anyone is reading this commit message, DO NOT DEPLOY IT IN A HOSTILE-FACING ENVIRONMENT! Its purpose is to speak the server end of everything PuTTY speaks on the client side, so that I can test that I haven't broken PuTTY when I reorganise its code, even things like RSA key exchange or chained auth methods which it's hard to find a server that speaks at all. (For this reason, it's declared with [UT] in the Recipe file, so that it falls into the same category as programs like testbn, which won't be installed by 'make install'.) Working title is 'Uppity', partly for 'Universal PuTTY Protocol Interaction Test Yoke', but mostly because it looks quite like the word 'PuTTY' with part of it reversed. (Apparently 'test yoke' is a very rarely used term meaning something not altogether unlike 'test harness', which is a bit of a stretch, but it'll do.) It doesn't actually _support_ everything I want yet. At the moment, it's a proof of concept only. But it has most of the machinery present, and the parts it's missing - such as chained auth methods - should be easy enough to add because I've built in the required flexibility, in the form of an AuthPolicy object which can request them if it wants to. However, the current AuthPolicy object is entirely trivial, and will let in any user with the password "weasel". (Another way in which this is not a production-ready server is that it also has no interaction with the OS's authentication system. In particular, it will not only let in any user with the same password, but it won't even change uid - it will open shells and forwardings under whatever user id you started it up as.) Currently, the program can only speak the SSH protocol on its standard I/O channels (using the new FdSocket facility), so if you want it to listen on a network port, you'll have to run it from some kind of separate listening program similar to inetd. For my own tests, I'm not even doing that: I'm just having PuTTY spawn it as a local proxy process, which also conveniently eliminates the risk of anyone hostile connecting to it. The bulk of the actual code reorganisation is already done by previous commits, so this change is _mostly_ just dropping in a new set of server-specific source files alongside the client-specific ones I created recently. The remaining changes in the shared SSH code are numerous, but all minor: - a few extra parameters to BPP and PPL constructors (e.g. 'are you in server mode?'), and pass both sets of SSH-1 protocol flags from the login to the connection layer - in server mode, unconditionally send our version string _before_ waiting for the remote one - a new hook in the SSH-1 BPP to handle enabling compression in server mode, where the message exchange works the other way round - new code in the SSH-2 BPP to do _deferred_ compression the other way round (the non-deferred version is still nicely symmetric) - in the SSH-2 transport layer, some adjustments to do key derivation either way round (swapping round the identifying letters in the various hash preimages, and making sure to list the KEXINITs in the right order) - also in the SSH-2 transport layer, an if statement that controls whether we send SERVICE_REQUEST and wait for SERVICE_ACCEPT, or vice versa - new ConnectionLayer methods for opening outgoing channels for X and agent forwardings - new functions in portfwd.c to establish listening sockets suitable for remote-to-local port forwarding (i.e. not under the direction of a Conf the way it's done on the client side).
2018-10-20 21:09:54 +00:00
SshChannel *ssh1_serverside_x11_open(
ConnectionLayer *cl, Channel *chan, const SocketPeerInfo *pi)
{
assert(FALSE && "Should never be called in the client");
return NULL;
}
SshChannel *ssh1_serverside_agent_open(ConnectionLayer *cl, Channel *chan)
{
assert(FALSE && "Should never be called in the client");
return NULL;
}