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
|
|
|
/*
|
|
|
|
* Implement the "session" channel type for the SSH server.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <assert.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <ctype.h>
|
|
|
|
|
|
|
|
#include "putty.h"
|
|
|
|
#include "ssh.h"
|
|
|
|
#include "sshchan.h"
|
|
|
|
#include "sshserver.h"
|
Add an SFTP server to the SSH server code.
Unlike the traditional Unix SSH server organisation, the SFTP server
is built into the same process as all the rest of the code. sesschan.c
spots a subsystem request for "sftp", and responds to it by
instantiating an SftpServer object and swapping out its own vtable for
one that talks to it.
(I rather like the idea of an object swapping its own vtable for a
different one in the middle of its lifetime! This is one of those
tricks that would be absurdly hard to implement in a 'proper' OO
language, but when you're doing vtables by hand in C, it's no more
difficult than any other piece of ordinary pointer manipulation. As
long as the methods in both vtables expect the same physical structure
layout, it doesn't cause a problem.)
The SftpServer object doesn't deal directly with SFTP packet formats;
it implements the SFTP server logic in a more abstract way, by having
a vtable method for each SFTP request type with an appropriate
parameter list. It sends its replies by calling methods in another
vtable called SftpReplyBuilder, which in the normal case will write an
SFTP reply packet to send back to the client. So SftpServer can focus
more or less completely on the details of a particular filesystem API
- and hence, the implementation I've got lives in the unix source
directory, and works directly with file descriptors and struct stat
and the like.
(One purpose of this abstraction layer is that I may well want to
write a second dummy implementation, for test-suite purposes, with
completely controllable behaviour, and now I have a handy place to
plug it in in place of the live filesystem.)
In between sesschan's parsing of the byte stream into SFTP packets and
the SftpServer object, there's a layer in the new file sftpserver.c
which does the actual packet decoding and encoding: each request
packet is passed to that, which pulls the fields out of the request
packet and calls the appropriate method of SftpServer. It also
provides the default SftpReplyBuilder which makes the output packet.
I've moved some code out of the previous SFTP client implementation -
basic packet construction code, and in particular the BinarySink/
BinarySource marshalling fuinction for fxp_attrs - into sftpcommon.c,
so that the two directions can share as much as possible.
2018-10-20 21:10:32 +00:00
|
|
|
#include "sftp.h"
|
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
|
|
|
|
|
|
|
typedef struct sesschan {
|
|
|
|
SshChannel *c;
|
|
|
|
|
|
|
|
LogContext *parent_logctx, *child_logctx;
|
|
|
|
Conf *conf;
|
Add an SFTP server to the SSH server code.
Unlike the traditional Unix SSH server organisation, the SFTP server
is built into the same process as all the rest of the code. sesschan.c
spots a subsystem request for "sftp", and responds to it by
instantiating an SftpServer object and swapping out its own vtable for
one that talks to it.
(I rather like the idea of an object swapping its own vtable for a
different one in the middle of its lifetime! This is one of those
tricks that would be absurdly hard to implement in a 'proper' OO
language, but when you're doing vtables by hand in C, it's no more
difficult than any other piece of ordinary pointer manipulation. As
long as the methods in both vtables expect the same physical structure
layout, it doesn't cause a problem.)
The SftpServer object doesn't deal directly with SFTP packet formats;
it implements the SFTP server logic in a more abstract way, by having
a vtable method for each SFTP request type with an appropriate
parameter list. It sends its replies by calling methods in another
vtable called SftpReplyBuilder, which in the normal case will write an
SFTP reply packet to send back to the client. So SftpServer can focus
more or less completely on the details of a particular filesystem API
- and hence, the implementation I've got lives in the unix source
directory, and works directly with file descriptors and struct stat
and the like.
(One purpose of this abstraction layer is that I may well want to
write a second dummy implementation, for test-suite purposes, with
completely controllable behaviour, and now I have a handy place to
plug it in in place of the live filesystem.)
In between sesschan's parsing of the byte stream into SFTP packets and
the SftpServer object, there's a layer in the new file sftpserver.c
which does the actual packet decoding and encoding: each request
packet is passed to that, which pulls the fields out of the request
packet and calls the appropriate method of SftpServer. It also
provides the default SftpReplyBuilder which makes the output packet.
I've moved some code out of the previous SFTP client implementation -
basic packet construction code, and in particular the BinarySink/
BinarySource marshalling fuinction for fxp_attrs - into sftpcommon.c,
so that the two directions can share as much as possible.
2018-10-20 21:10:32 +00:00
|
|
|
const SftpServerVtable *sftpserver_vt;
|
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
|
|
|
|
|
|
|
LogPolicy logpolicy;
|
|
|
|
Seat seat;
|
|
|
|
|
|
|
|
int want_pty;
|
|
|
|
struct ssh_ttymodes ttymodes;
|
|
|
|
int wc, hc, wp, hp;
|
|
|
|
strbuf *termtype;
|
|
|
|
|
|
|
|
int ignoring_input;
|
|
|
|
int seen_eof, seen_exit;
|
|
|
|
|
|
|
|
Plug xfwd_plug;
|
|
|
|
int n_x11_sockets;
|
|
|
|
Socket *x11_sockets[MAX_X11_SOCKETS];
|
|
|
|
|
|
|
|
Plug agentfwd_plug;
|
|
|
|
Socket *agentfwd_socket;
|
|
|
|
|
|
|
|
Backend *backend;
|
|
|
|
|
|
|
|
bufchain subsys_input;
|
Add an SFTP server to the SSH server code.
Unlike the traditional Unix SSH server organisation, the SFTP server
is built into the same process as all the rest of the code. sesschan.c
spots a subsystem request for "sftp", and responds to it by
instantiating an SftpServer object and swapping out its own vtable for
one that talks to it.
(I rather like the idea of an object swapping its own vtable for a
different one in the middle of its lifetime! This is one of those
tricks that would be absurdly hard to implement in a 'proper' OO
language, but when you're doing vtables by hand in C, it's no more
difficult than any other piece of ordinary pointer manipulation. As
long as the methods in both vtables expect the same physical structure
layout, it doesn't cause a problem.)
The SftpServer object doesn't deal directly with SFTP packet formats;
it implements the SFTP server logic in a more abstract way, by having
a vtable method for each SFTP request type with an appropriate
parameter list. It sends its replies by calling methods in another
vtable called SftpReplyBuilder, which in the normal case will write an
SFTP reply packet to send back to the client. So SftpServer can focus
more or less completely on the details of a particular filesystem API
- and hence, the implementation I've got lives in the unix source
directory, and works directly with file descriptors and struct stat
and the like.
(One purpose of this abstraction layer is that I may well want to
write a second dummy implementation, for test-suite purposes, with
completely controllable behaviour, and now I have a handy place to
plug it in in place of the live filesystem.)
In between sesschan's parsing of the byte stream into SFTP packets and
the SftpServer object, there's a layer in the new file sftpserver.c
which does the actual packet decoding and encoding: each request
packet is passed to that, which pulls the fields out of the request
packet and calls the appropriate method of SftpServer. It also
provides the default SftpReplyBuilder which makes the output packet.
I've moved some code out of the previous SFTP client implementation -
basic packet construction code, and in particular the BinarySink/
BinarySource marshalling fuinction for fxp_attrs - into sftpcommon.c,
so that the two directions can share as much as possible.
2018-10-20 21:10:32 +00:00
|
|
|
SftpServer *sftpsrv;
|
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
|
|
|
|
|
|
|
Channel chan;
|
|
|
|
} sesschan;
|
|
|
|
|
|
|
|
static void sesschan_free(Channel *chan);
|
|
|
|
static int sesschan_send(Channel *chan, int is_stderr, const void *, int);
|
|
|
|
static void sesschan_send_eof(Channel *chan);
|
|
|
|
static char *sesschan_log_close_msg(Channel *chan);
|
|
|
|
static int sesschan_want_close(Channel *, int, int);
|
|
|
|
static void sesschan_set_input_wanted(Channel *chan, int wanted);
|
|
|
|
static int sesschan_run_shell(Channel *chan);
|
|
|
|
static int sesschan_run_command(Channel *chan, ptrlen command);
|
|
|
|
static int sesschan_run_subsystem(Channel *chan, ptrlen subsys);
|
|
|
|
static int sesschan_enable_x11_forwarding(
|
|
|
|
Channel *chan, int oneshot, ptrlen authproto, ptrlen authdata,
|
|
|
|
unsigned screen_number);
|
|
|
|
static int sesschan_enable_agent_forwarding(Channel *chan);
|
|
|
|
static int sesschan_allocate_pty(
|
|
|
|
Channel *chan, ptrlen termtype, unsigned width, unsigned height,
|
|
|
|
unsigned pixwidth, unsigned pixheight, struct ssh_ttymodes modes);
|
|
|
|
static int sesschan_set_env(Channel *chan, ptrlen var, ptrlen value);
|
|
|
|
static int sesschan_send_break(Channel *chan, unsigned length);
|
|
|
|
static int sesschan_send_signal(Channel *chan, ptrlen signame);
|
|
|
|
static int sesschan_change_window_size(
|
|
|
|
Channel *chan, unsigned width, unsigned height,
|
|
|
|
unsigned pixwidth, unsigned pixheight);
|
|
|
|
|
|
|
|
static const struct ChannelVtable sesschan_channelvt = {
|
|
|
|
sesschan_free,
|
|
|
|
chan_remotely_opened_confirmation,
|
|
|
|
chan_remotely_opened_failure,
|
|
|
|
sesschan_send,
|
|
|
|
sesschan_send_eof,
|
|
|
|
sesschan_set_input_wanted,
|
|
|
|
sesschan_log_close_msg,
|
|
|
|
sesschan_want_close,
|
|
|
|
chan_no_exit_status,
|
|
|
|
chan_no_exit_signal,
|
|
|
|
chan_no_exit_signal_numeric,
|
|
|
|
sesschan_run_shell,
|
|
|
|
sesschan_run_command,
|
|
|
|
sesschan_run_subsystem,
|
|
|
|
sesschan_enable_x11_forwarding,
|
|
|
|
sesschan_enable_agent_forwarding,
|
|
|
|
sesschan_allocate_pty,
|
|
|
|
sesschan_set_env,
|
|
|
|
sesschan_send_break,
|
|
|
|
sesschan_send_signal,
|
|
|
|
sesschan_change_window_size,
|
|
|
|
chan_no_request_response,
|
|
|
|
};
|
|
|
|
|
Add an SFTP server to the SSH server code.
Unlike the traditional Unix SSH server organisation, the SFTP server
is built into the same process as all the rest of the code. sesschan.c
spots a subsystem request for "sftp", and responds to it by
instantiating an SftpServer object and swapping out its own vtable for
one that talks to it.
(I rather like the idea of an object swapping its own vtable for a
different one in the middle of its lifetime! This is one of those
tricks that would be absurdly hard to implement in a 'proper' OO
language, but when you're doing vtables by hand in C, it's no more
difficult than any other piece of ordinary pointer manipulation. As
long as the methods in both vtables expect the same physical structure
layout, it doesn't cause a problem.)
The SftpServer object doesn't deal directly with SFTP packet formats;
it implements the SFTP server logic in a more abstract way, by having
a vtable method for each SFTP request type with an appropriate
parameter list. It sends its replies by calling methods in another
vtable called SftpReplyBuilder, which in the normal case will write an
SFTP reply packet to send back to the client. So SftpServer can focus
more or less completely on the details of a particular filesystem API
- and hence, the implementation I've got lives in the unix source
directory, and works directly with file descriptors and struct stat
and the like.
(One purpose of this abstraction layer is that I may well want to
write a second dummy implementation, for test-suite purposes, with
completely controllable behaviour, and now I have a handy place to
plug it in in place of the live filesystem.)
In between sesschan's parsing of the byte stream into SFTP packets and
the SftpServer object, there's a layer in the new file sftpserver.c
which does the actual packet decoding and encoding: each request
packet is passed to that, which pulls the fields out of the request
packet and calls the appropriate method of SftpServer. It also
provides the default SftpReplyBuilder which makes the output packet.
I've moved some code out of the previous SFTP client implementation -
basic packet construction code, and in particular the BinarySink/
BinarySource marshalling fuinction for fxp_attrs - into sftpcommon.c,
so that the two directions can share as much as possible.
2018-10-20 21:10:32 +00:00
|
|
|
static int sftp_chan_send(Channel *chan, int is_stderr, const void *, int);
|
|
|
|
static void sftp_chan_send_eof(Channel *chan);
|
|
|
|
static char *sftp_log_close_msg(Channel *chan);
|
|
|
|
|
|
|
|
static const struct ChannelVtable sftp_channelvt = {
|
|
|
|
sesschan_free,
|
|
|
|
chan_remotely_opened_confirmation,
|
|
|
|
chan_remotely_opened_failure,
|
|
|
|
sftp_chan_send,
|
|
|
|
sftp_chan_send_eof,
|
|
|
|
sesschan_set_input_wanted,
|
|
|
|
sftp_log_close_msg,
|
|
|
|
chan_default_want_close,
|
|
|
|
chan_no_exit_status,
|
|
|
|
chan_no_exit_signal,
|
|
|
|
chan_no_exit_signal_numeric,
|
|
|
|
chan_no_run_shell,
|
|
|
|
chan_no_run_command,
|
|
|
|
chan_no_run_subsystem,
|
|
|
|
chan_no_enable_x11_forwarding,
|
|
|
|
chan_no_enable_agent_forwarding,
|
|
|
|
chan_no_allocate_pty,
|
|
|
|
chan_no_set_env,
|
|
|
|
chan_no_send_break,
|
|
|
|
chan_no_send_signal,
|
|
|
|
chan_no_change_window_size,
|
|
|
|
chan_no_request_response,
|
|
|
|
};
|
|
|
|
|
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
|
|
|
static void sesschan_eventlog(LogPolicy *lp, const char *event) {}
|
|
|
|
static void sesschan_logging_error(LogPolicy *lp, const char *event) {}
|
|
|
|
static int sesschan_askappend(
|
|
|
|
LogPolicy *lp, Filename *filename,
|
|
|
|
void (*callback)(void *ctx, int result), void *ctx) { return 2; }
|
|
|
|
|
|
|
|
static const LogPolicyVtable sesschan_logpolicy_vt = {
|
|
|
|
sesschan_eventlog,
|
|
|
|
sesschan_askappend,
|
|
|
|
sesschan_logging_error,
|
|
|
|
};
|
|
|
|
|
|
|
|
static int sesschan_seat_output(Seat *, int is_stderr, const void *, int);
|
|
|
|
static int sesschan_seat_eof(Seat *);
|
|
|
|
static void sesschan_notify_remote_exit(Seat *seat);
|
|
|
|
static void sesschan_connection_fatal(Seat *seat, const char *message);
|
|
|
|
static int sesschan_get_window_pixel_size(Seat *seat, int *width, int *height);
|
|
|
|
|
|
|
|
static const SeatVtable sesschan_seat_vt = {
|
|
|
|
sesschan_seat_output,
|
|
|
|
sesschan_seat_eof,
|
|
|
|
nullseat_get_userpass_input,
|
|
|
|
sesschan_notify_remote_exit,
|
|
|
|
sesschan_connection_fatal,
|
|
|
|
nullseat_update_specials_menu,
|
|
|
|
nullseat_get_ttymode,
|
|
|
|
nullseat_set_busy_status,
|
|
|
|
nullseat_verify_ssh_host_key,
|
|
|
|
nullseat_confirm_weak_crypto_primitive,
|
|
|
|
nullseat_confirm_weak_cached_hostkey,
|
|
|
|
nullseat_is_never_utf8,
|
|
|
|
nullseat_echoedit_update,
|
|
|
|
nullseat_get_x_display,
|
|
|
|
nullseat_get_windowid,
|
|
|
|
sesschan_get_window_pixel_size,
|
|
|
|
};
|
|
|
|
|
Add an SFTP server to the SSH server code.
Unlike the traditional Unix SSH server organisation, the SFTP server
is built into the same process as all the rest of the code. sesschan.c
spots a subsystem request for "sftp", and responds to it by
instantiating an SftpServer object and swapping out its own vtable for
one that talks to it.
(I rather like the idea of an object swapping its own vtable for a
different one in the middle of its lifetime! This is one of those
tricks that would be absurdly hard to implement in a 'proper' OO
language, but when you're doing vtables by hand in C, it's no more
difficult than any other piece of ordinary pointer manipulation. As
long as the methods in both vtables expect the same physical structure
layout, it doesn't cause a problem.)
The SftpServer object doesn't deal directly with SFTP packet formats;
it implements the SFTP server logic in a more abstract way, by having
a vtable method for each SFTP request type with an appropriate
parameter list. It sends its replies by calling methods in another
vtable called SftpReplyBuilder, which in the normal case will write an
SFTP reply packet to send back to the client. So SftpServer can focus
more or less completely on the details of a particular filesystem API
- and hence, the implementation I've got lives in the unix source
directory, and works directly with file descriptors and struct stat
and the like.
(One purpose of this abstraction layer is that I may well want to
write a second dummy implementation, for test-suite purposes, with
completely controllable behaviour, and now I have a handy place to
plug it in in place of the live filesystem.)
In between sesschan's parsing of the byte stream into SFTP packets and
the SftpServer object, there's a layer in the new file sftpserver.c
which does the actual packet decoding and encoding: each request
packet is passed to that, which pulls the fields out of the request
packet and calls the appropriate method of SftpServer. It also
provides the default SftpReplyBuilder which makes the output packet.
I've moved some code out of the previous SFTP client implementation -
basic packet construction code, and in particular the BinarySink/
BinarySource marshalling fuinction for fxp_attrs - into sftpcommon.c,
so that the two directions can share as much as possible.
2018-10-20 21:10:32 +00:00
|
|
|
Channel *sesschan_new(SshChannel *c, LogContext *logctx,
|
|
|
|
const SftpServerVtable *sftpserver_vt)
|
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
|
|
|
{
|
|
|
|
sesschan *sess = snew(sesschan);
|
|
|
|
memset(sess, 0, sizeof(sesschan));
|
|
|
|
|
|
|
|
sess->c = c;
|
|
|
|
sess->chan.vt = &sesschan_channelvt;
|
|
|
|
sess->chan.initial_fixed_window_size = 0;
|
|
|
|
sess->parent_logctx = logctx;
|
|
|
|
|
|
|
|
/* Start with a completely default Conf */
|
|
|
|
sess->conf = conf_new();
|
|
|
|
load_open_settings(NULL, sess->conf);
|
|
|
|
|
|
|
|
/* Set close-on-exit = TRUE to suppress uxpty.c's "[pterm: process
|
|
|
|
* terminated with status x]" message */
|
|
|
|
conf_set_int(sess->conf, CONF_close_on_exit, FORCE_ON);
|
|
|
|
|
|
|
|
sess->seat.vt = &sesschan_seat_vt;
|
|
|
|
sess->logpolicy.vt = &sesschan_logpolicy_vt;
|
|
|
|
sess->child_logctx = log_init(&sess->logpolicy, sess->conf);
|
|
|
|
|
Add an SFTP server to the SSH server code.
Unlike the traditional Unix SSH server organisation, the SFTP server
is built into the same process as all the rest of the code. sesschan.c
spots a subsystem request for "sftp", and responds to it by
instantiating an SftpServer object and swapping out its own vtable for
one that talks to it.
(I rather like the idea of an object swapping its own vtable for a
different one in the middle of its lifetime! This is one of those
tricks that would be absurdly hard to implement in a 'proper' OO
language, but when you're doing vtables by hand in C, it's no more
difficult than any other piece of ordinary pointer manipulation. As
long as the methods in both vtables expect the same physical structure
layout, it doesn't cause a problem.)
The SftpServer object doesn't deal directly with SFTP packet formats;
it implements the SFTP server logic in a more abstract way, by having
a vtable method for each SFTP request type with an appropriate
parameter list. It sends its replies by calling methods in another
vtable called SftpReplyBuilder, which in the normal case will write an
SFTP reply packet to send back to the client. So SftpServer can focus
more or less completely on the details of a particular filesystem API
- and hence, the implementation I've got lives in the unix source
directory, and works directly with file descriptors and struct stat
and the like.
(One purpose of this abstraction layer is that I may well want to
write a second dummy implementation, for test-suite purposes, with
completely controllable behaviour, and now I have a handy place to
plug it in in place of the live filesystem.)
In between sesschan's parsing of the byte stream into SFTP packets and
the SftpServer object, there's a layer in the new file sftpserver.c
which does the actual packet decoding and encoding: each request
packet is passed to that, which pulls the fields out of the request
packet and calls the appropriate method of SftpServer. It also
provides the default SftpReplyBuilder which makes the output packet.
I've moved some code out of the previous SFTP client implementation -
basic packet construction code, and in particular the BinarySink/
BinarySource marshalling fuinction for fxp_attrs - into sftpcommon.c,
so that the two directions can share as much as possible.
2018-10-20 21:10:32 +00:00
|
|
|
sess->sftpserver_vt = sftpserver_vt;
|
|
|
|
|
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
|
|
|
bufchain_init(&sess->subsys_input);
|
|
|
|
|
|
|
|
return &sess->chan;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void sesschan_free(Channel *chan)
|
|
|
|
{
|
|
|
|
sesschan *sess = container_of(chan, sesschan, chan);
|
|
|
|
int i;
|
|
|
|
|
|
|
|
delete_callbacks_for_context(sess);
|
|
|
|
conf_free(sess->conf);
|
|
|
|
if (sess->backend)
|
|
|
|
backend_free(sess->backend);
|
|
|
|
bufchain_clear(&sess->subsys_input);
|
Add an SFTP server to the SSH server code.
Unlike the traditional Unix SSH server organisation, the SFTP server
is built into the same process as all the rest of the code. sesschan.c
spots a subsystem request for "sftp", and responds to it by
instantiating an SftpServer object and swapping out its own vtable for
one that talks to it.
(I rather like the idea of an object swapping its own vtable for a
different one in the middle of its lifetime! This is one of those
tricks that would be absurdly hard to implement in a 'proper' OO
language, but when you're doing vtables by hand in C, it's no more
difficult than any other piece of ordinary pointer manipulation. As
long as the methods in both vtables expect the same physical structure
layout, it doesn't cause a problem.)
The SftpServer object doesn't deal directly with SFTP packet formats;
it implements the SFTP server logic in a more abstract way, by having
a vtable method for each SFTP request type with an appropriate
parameter list. It sends its replies by calling methods in another
vtable called SftpReplyBuilder, which in the normal case will write an
SFTP reply packet to send back to the client. So SftpServer can focus
more or less completely on the details of a particular filesystem API
- and hence, the implementation I've got lives in the unix source
directory, and works directly with file descriptors and struct stat
and the like.
(One purpose of this abstraction layer is that I may well want to
write a second dummy implementation, for test-suite purposes, with
completely controllable behaviour, and now I have a handy place to
plug it in in place of the live filesystem.)
In between sesschan's parsing of the byte stream into SFTP packets and
the SftpServer object, there's a layer in the new file sftpserver.c
which does the actual packet decoding and encoding: each request
packet is passed to that, which pulls the fields out of the request
packet and calls the appropriate method of SftpServer. It also
provides the default SftpReplyBuilder which makes the output packet.
I've moved some code out of the previous SFTP client implementation -
basic packet construction code, and in particular the BinarySink/
BinarySource marshalling fuinction for fxp_attrs - into sftpcommon.c,
so that the two directions can share as much as possible.
2018-10-20 21:10:32 +00:00
|
|
|
if (sess->sftpsrv)
|
|
|
|
sftpsrv_free(sess->sftpsrv);
|
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
|
|
|
for (i = 0; i < sess->n_x11_sockets; i++)
|
|
|
|
sk_close(sess->x11_sockets[i]);
|
|
|
|
if (sess->agentfwd_socket)
|
|
|
|
sk_close(sess->agentfwd_socket);
|
|
|
|
|
|
|
|
sfree(sess);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int sesschan_send(Channel *chan, int is_stderr,
|
|
|
|
const void *data, int length)
|
|
|
|
{
|
|
|
|
sesschan *sess = container_of(chan, sesschan, chan);
|
|
|
|
|
|
|
|
if (!sess->backend || sess->ignoring_input)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return backend_send(sess->backend, data, length);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void sesschan_send_eof(Channel *chan)
|
|
|
|
{
|
|
|
|
sesschan *sess = container_of(chan, sesschan, chan);
|
|
|
|
if (sess->backend)
|
|
|
|
backend_special(sess->backend, SS_EOF, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static char *sesschan_log_close_msg(Channel *chan)
|
|
|
|
{
|
|
|
|
return dupstr("Session channel closed");
|
|
|
|
}
|
|
|
|
|
|
|
|
static void sesschan_set_input_wanted(Channel *chan, int wanted)
|
|
|
|
{
|
|
|
|
/* I don't think we need to do anything here */
|
|
|
|
}
|
|
|
|
|
|
|
|
static void sesschan_start_backend(sesschan *sess, const char *cmd)
|
|
|
|
{
|
|
|
|
sess->backend = pty_backend_create(
|
|
|
|
&sess->seat, sess->child_logctx, sess->conf, NULL, cmd,
|
|
|
|
sess->ttymodes, !sess->want_pty);
|
|
|
|
backend_size(sess->backend, sess->wc, sess->hc);
|
|
|
|
}
|
|
|
|
|
|
|
|
int sesschan_run_shell(Channel *chan)
|
|
|
|
{
|
|
|
|
sesschan *sess = container_of(chan, sesschan, chan);
|
|
|
|
|
|
|
|
if (sess->backend)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
sesschan_start_backend(sess, NULL);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
int sesschan_run_command(Channel *chan, ptrlen command)
|
|
|
|
{
|
|
|
|
sesschan *sess = container_of(chan, sesschan, chan);
|
|
|
|
|
|
|
|
if (sess->backend)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
char *command_str = mkstr(command);
|
|
|
|
sesschan_start_backend(sess, command_str);
|
|
|
|
sfree(command_str);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
int sesschan_run_subsystem(Channel *chan, ptrlen subsys)
|
|
|
|
{
|
Add an SFTP server to the SSH server code.
Unlike the traditional Unix SSH server organisation, the SFTP server
is built into the same process as all the rest of the code. sesschan.c
spots a subsystem request for "sftp", and responds to it by
instantiating an SftpServer object and swapping out its own vtable for
one that talks to it.
(I rather like the idea of an object swapping its own vtable for a
different one in the middle of its lifetime! This is one of those
tricks that would be absurdly hard to implement in a 'proper' OO
language, but when you're doing vtables by hand in C, it's no more
difficult than any other piece of ordinary pointer manipulation. As
long as the methods in both vtables expect the same physical structure
layout, it doesn't cause a problem.)
The SftpServer object doesn't deal directly with SFTP packet formats;
it implements the SFTP server logic in a more abstract way, by having
a vtable method for each SFTP request type with an appropriate
parameter list. It sends its replies by calling methods in another
vtable called SftpReplyBuilder, which in the normal case will write an
SFTP reply packet to send back to the client. So SftpServer can focus
more or less completely on the details of a particular filesystem API
- and hence, the implementation I've got lives in the unix source
directory, and works directly with file descriptors and struct stat
and the like.
(One purpose of this abstraction layer is that I may well want to
write a second dummy implementation, for test-suite purposes, with
completely controllable behaviour, and now I have a handy place to
plug it in in place of the live filesystem.)
In between sesschan's parsing of the byte stream into SFTP packets and
the SftpServer object, there's a layer in the new file sftpserver.c
which does the actual packet decoding and encoding: each request
packet is passed to that, which pulls the fields out of the request
packet and calls the appropriate method of SftpServer. It also
provides the default SftpReplyBuilder which makes the output packet.
I've moved some code out of the previous SFTP client implementation -
basic packet construction code, and in particular the BinarySink/
BinarySource marshalling fuinction for fxp_attrs - into sftpcommon.c,
so that the two directions can share as much as possible.
2018-10-20 21:10:32 +00:00
|
|
|
sesschan *sess = container_of(chan, sesschan, chan);
|
|
|
|
|
|
|
|
if (ptrlen_eq_string(subsys, "sftp") && sess->sftpserver_vt) {
|
|
|
|
sess->sftpsrv = sftpsrv_new(sess->sftpserver_vt);
|
|
|
|
sess->chan.vt = &sftp_channelvt;
|
|
|
|
logevent(sess->parent_logctx, "Starting built-in SFTP subsystem");
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
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
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void fwd_log(Plug *plug, int type, SockAddr *addr, int port,
|
|
|
|
const char *error_msg, int error_code)
|
|
|
|
{ /* don't expect any weirdnesses from a listening socket */ }
|
|
|
|
static void fwd_closing(Plug *plug, const char *error_msg, int error_code,
|
|
|
|
int calling_back)
|
|
|
|
{ /* not here, either */ }
|
|
|
|
|
|
|
|
static int xfwd_accepting(Plug *p, accept_fn_t constructor, accept_ctx_t ctx)
|
|
|
|
{
|
|
|
|
sesschan *sess = container_of(p, sesschan, xfwd_plug);
|
|
|
|
Plug *plug;
|
|
|
|
Channel *chan;
|
|
|
|
Socket *s;
|
|
|
|
SocketPeerInfo *pi;
|
|
|
|
const char *err;
|
|
|
|
|
|
|
|
chan = portfwd_raw_new(sess->c->cl, &plug);
|
|
|
|
s = constructor(ctx, plug);
|
|
|
|
if ((err = sk_socket_error(s)) != NULL) {
|
|
|
|
portfwd_raw_free(chan);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
pi = sk_peer_info(s);
|
|
|
|
portfwd_raw_setup(chan, s, ssh_serverside_x11_open(sess->c->cl, chan, pi));
|
|
|
|
sk_free_peer_info(pi);
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const PlugVtable xfwd_plugvt = {
|
|
|
|
fwd_log,
|
|
|
|
fwd_closing,
|
|
|
|
NULL, /* recv */
|
|
|
|
NULL, /* send */
|
|
|
|
xfwd_accepting,
|
|
|
|
};
|
|
|
|
|
|
|
|
int sesschan_enable_x11_forwarding(
|
|
|
|
Channel *chan, int oneshot, ptrlen authproto, ptrlen authdata_hex,
|
|
|
|
unsigned screen_number)
|
|
|
|
{
|
|
|
|
sesschan *sess = container_of(chan, sesschan, chan);
|
|
|
|
strbuf *authdata_bin;
|
|
|
|
size_t i;
|
|
|
|
char screensuffix[32];
|
|
|
|
|
|
|
|
if (oneshot)
|
|
|
|
return FALSE; /* not supported */
|
|
|
|
|
|
|
|
snprintf(screensuffix, sizeof(screensuffix), ".%u", screen_number);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Decode the authorisation data from ASCII hex into binary.
|
|
|
|
*/
|
|
|
|
if (authdata_hex.len % 2)
|
|
|
|
return FALSE; /* expected an even number of digits */
|
|
|
|
authdata_bin = strbuf_new();
|
|
|
|
for (i = 0; i < authdata_hex.len; i += 2) {
|
|
|
|
const unsigned char *hex = authdata_hex.ptr;
|
|
|
|
char hexbuf[3];
|
|
|
|
|
|
|
|
if (!isxdigit(hex[i]) || !isxdigit(hex[i+1])) {
|
|
|
|
strbuf_free(authdata_bin);
|
|
|
|
return FALSE; /* not hex */
|
|
|
|
}
|
|
|
|
|
|
|
|
hexbuf[0] = hex[i];
|
|
|
|
hexbuf[1] = hex[i+1];
|
|
|
|
hexbuf[2] = '\0';
|
|
|
|
put_byte(authdata_bin, strtoul(hexbuf, NULL, 16));
|
|
|
|
}
|
|
|
|
|
|
|
|
sess->xfwd_plug.vt = &xfwd_plugvt;
|
|
|
|
|
|
|
|
sess->n_x11_sockets = platform_make_x11_server(
|
|
|
|
&sess->xfwd_plug, appname, 10, screensuffix,
|
|
|
|
authproto, ptrlen_from_strbuf(authdata_bin),
|
|
|
|
sess->x11_sockets, sess->conf);
|
|
|
|
|
|
|
|
strbuf_free(authdata_bin);
|
|
|
|
return sess->n_x11_sockets != 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int agentfwd_accepting(
|
|
|
|
Plug *p, accept_fn_t constructor, accept_ctx_t ctx)
|
|
|
|
{
|
|
|
|
sesschan *sess = container_of(p, sesschan, agentfwd_plug);
|
|
|
|
Plug *plug;
|
|
|
|
Channel *chan;
|
|
|
|
Socket *s;
|
|
|
|
const char *err;
|
|
|
|
|
|
|
|
chan = portfwd_raw_new(sess->c->cl, &plug);
|
|
|
|
s = constructor(ctx, plug);
|
|
|
|
if ((err = sk_socket_error(s)) != NULL) {
|
|
|
|
portfwd_raw_free(chan);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
portfwd_raw_setup(chan, s, ssh_serverside_agent_open(sess->c->cl, chan));
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const PlugVtable agentfwd_plugvt = {
|
|
|
|
fwd_log,
|
|
|
|
fwd_closing,
|
|
|
|
NULL, /* recv */
|
|
|
|
NULL, /* send */
|
|
|
|
agentfwd_accepting,
|
|
|
|
};
|
|
|
|
|
|
|
|
int sesschan_enable_agent_forwarding(Channel *chan)
|
|
|
|
{
|
|
|
|
sesschan *sess = container_of(chan, sesschan, chan);
|
|
|
|
char *error, *socketname, *dir_prefix;
|
|
|
|
|
|
|
|
dir_prefix = dupprintf("/tmp/%s-agentfwd", appname);
|
|
|
|
|
|
|
|
sess->agentfwd_plug.vt = &agentfwd_plugvt;
|
|
|
|
sess->agentfwd_socket = platform_make_agent_socket(
|
|
|
|
&sess->agentfwd_plug, dir_prefix, &error, &socketname);
|
|
|
|
|
|
|
|
sfree(dir_prefix);
|
|
|
|
|
|
|
|
if (sess->agentfwd_socket) {
|
|
|
|
conf_set_str_str(sess->conf, CONF_environmt,
|
|
|
|
"SSH_AUTH_SOCK", socketname);
|
|
|
|
}
|
|
|
|
|
|
|
|
sfree(error);
|
|
|
|
sfree(socketname);
|
|
|
|
|
|
|
|
return sess->agentfwd_socket != NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
int sesschan_allocate_pty(
|
|
|
|
Channel *chan, ptrlen termtype, unsigned width, unsigned height,
|
|
|
|
unsigned pixwidth, unsigned pixheight, struct ssh_ttymodes modes)
|
|
|
|
{
|
|
|
|
sesschan *sess = container_of(chan, sesschan, chan);
|
|
|
|
char *s;
|
|
|
|
|
|
|
|
if (sess->want_pty)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
s = mkstr(termtype);
|
|
|
|
conf_set_str(sess->conf, CONF_termtype, s);
|
|
|
|
sfree(s);
|
|
|
|
|
|
|
|
sess->want_pty = TRUE;
|
|
|
|
sess->ttymodes = modes;
|
|
|
|
sess->wc = width;
|
|
|
|
sess->hc = height;
|
|
|
|
sess->wp = pixwidth;
|
|
|
|
sess->hp = pixheight;
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
int sesschan_set_env(Channel *chan, ptrlen var, ptrlen value)
|
|
|
|
{
|
|
|
|
sesschan *sess = container_of(chan, sesschan, chan);
|
|
|
|
|
|
|
|
char *svar = mkstr(var), *svalue = mkstr(value);
|
|
|
|
conf_set_str_str(sess->conf, CONF_environmt, svar, svalue);
|
|
|
|
sfree(svar);
|
|
|
|
sfree(svalue);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
int sesschan_send_break(Channel *chan, unsigned length)
|
|
|
|
{
|
|
|
|
sesschan *sess = container_of(chan, sesschan, chan);
|
|
|
|
|
|
|
|
if (sess->backend) {
|
|
|
|
/* We ignore the break length. We could pass it through as the
|
|
|
|
* 'arg' parameter, and have uxpty.c collect it and pass it on
|
|
|
|
* to tcsendbreak, but since tcsendbreak in turn assigns
|
|
|
|
* implementation-defined semantics to _its_ duration
|
|
|
|
* parameter, this all just sounds too difficult. */
|
|
|
|
backend_special(sess->backend, SS_BRK, 0);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
int sesschan_send_signal(Channel *chan, ptrlen signame)
|
|
|
|
{
|
|
|
|
sesschan *sess = container_of(chan, sesschan, chan);
|
|
|
|
|
|
|
|
/* Start with a code that definitely isn't a signal (or indeed a
|
|
|
|
* special command at all), to indicate 'nothing matched'. */
|
|
|
|
SessionSpecialCode code = SS_EXITMENU;
|
|
|
|
|
|
|
|
#define SIGNAL_SUB(name) \
|
|
|
|
if (ptrlen_eq_string(signame, #name)) code = SS_SIG ## name;
|
|
|
|
#define SIGNAL_MAIN(name, text) SIGNAL_SUB(name)
|
|
|
|
#include "sshsignals.h"
|
|
|
|
#undef SIGNAL_MAIN
|
|
|
|
#undef SIGNAL_SUB
|
|
|
|
|
|
|
|
if (code == SS_EXITMENU)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
backend_special(sess->backend, code, 0);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
int sesschan_change_window_size(
|
|
|
|
Channel *chan, unsigned width, unsigned height,
|
|
|
|
unsigned pixwidth, unsigned pixheight)
|
|
|
|
{
|
|
|
|
sesschan *sess = container_of(chan, sesschan, chan);
|
|
|
|
|
|
|
|
if (!sess->want_pty)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
sess->wc = width;
|
|
|
|
sess->hc = height;
|
|
|
|
sess->wp = pixwidth;
|
|
|
|
sess->hp = pixheight;
|
|
|
|
|
|
|
|
if (sess->backend)
|
|
|
|
backend_size(sess->backend, sess->wc, sess->hc);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int sesschan_seat_output(
|
|
|
|
Seat *seat, int is_stderr, const void *data, int len)
|
|
|
|
{
|
|
|
|
sesschan *sess = container_of(seat, sesschan, seat);
|
|
|
|
return sshfwd_write_ext(sess->c, is_stderr, data, len);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void sesschan_check_close_callback(void *vctx)
|
|
|
|
{
|
|
|
|
sesschan *sess = (sesschan *)vctx;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Once we've seen incoming EOF from the backend (aka EIO from the
|
|
|
|
* pty master) and also passed on the process's exit status, we
|
|
|
|
* should proactively initiate closure of the session channel.
|
|
|
|
*/
|
|
|
|
if (sess->seen_eof && sess->seen_exit)
|
|
|
|
sshfwd_initiate_close(sess->c, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int sesschan_want_close(Channel *chan, int seen_eof, int rcvd_eof)
|
|
|
|
{
|
|
|
|
sesschan *sess = container_of(chan, sesschan, chan);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Similarly to above, we don't want to initiate channel closure
|
|
|
|
* until we've sent the process's exit status, _even_ if EOF of
|
|
|
|
* the actual data stream has happened in both directions.
|
|
|
|
*/
|
|
|
|
return (sess->seen_eof && sess->seen_exit);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int sesschan_seat_eof(Seat *seat)
|
|
|
|
{
|
|
|
|
sesschan *sess = container_of(seat, sesschan, seat);
|
|
|
|
|
|
|
|
sshfwd_write_eof(sess->c);
|
|
|
|
sess->seen_eof = TRUE;
|
|
|
|
|
|
|
|
queue_toplevel_callback(sesschan_check_close_callback, sess);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void sesschan_notify_remote_exit(Seat *seat)
|
|
|
|
{
|
|
|
|
sesschan *sess = container_of(seat, sesschan, seat);
|
|
|
|
ptrlen signame;
|
|
|
|
char *sigmsg;
|
|
|
|
|
|
|
|
if (!sess->backend)
|
|
|
|
return;
|
|
|
|
|
|
|
|
signame = pty_backend_exit_signame(sess->backend, &sigmsg);
|
|
|
|
if (signame.len) {
|
|
|
|
if (!sigmsg)
|
|
|
|
sigmsg = dupstr("");
|
|
|
|
|
|
|
|
sshfwd_send_exit_signal(
|
|
|
|
sess->c, signame, FALSE, ptrlen_from_asciz(sigmsg));
|
|
|
|
|
|
|
|
sfree(sigmsg);
|
|
|
|
} else {
|
|
|
|
sshfwd_send_exit_status(sess->c, backend_exitcode(sess->backend));
|
|
|
|
}
|
|
|
|
|
|
|
|
sess->seen_exit = TRUE;
|
|
|
|
queue_toplevel_callback(sesschan_check_close_callback, sess);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void sesschan_connection_fatal(Seat *seat, const char *message)
|
|
|
|
{
|
|
|
|
sesschan *sess = container_of(seat, sesschan, seat);
|
|
|
|
|
|
|
|
/* Closest translation I can think of */
|
|
|
|
sshfwd_send_exit_signal(
|
|
|
|
sess->c, PTRLEN_LITERAL("HUP"), FALSE, ptrlen_from_asciz(message));
|
|
|
|
|
|
|
|
sess->ignoring_input = TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int sesschan_get_window_pixel_size(Seat *seat, int *width, int *height)
|
|
|
|
{
|
|
|
|
sesschan *sess = container_of(seat, sesschan, seat);
|
|
|
|
|
|
|
|
*width = sess->wp;
|
|
|
|
*height = sess->hp;
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
Add an SFTP server to the SSH server code.
Unlike the traditional Unix SSH server organisation, the SFTP server
is built into the same process as all the rest of the code. sesschan.c
spots a subsystem request for "sftp", and responds to it by
instantiating an SftpServer object and swapping out its own vtable for
one that talks to it.
(I rather like the idea of an object swapping its own vtable for a
different one in the middle of its lifetime! This is one of those
tricks that would be absurdly hard to implement in a 'proper' OO
language, but when you're doing vtables by hand in C, it's no more
difficult than any other piece of ordinary pointer manipulation. As
long as the methods in both vtables expect the same physical structure
layout, it doesn't cause a problem.)
The SftpServer object doesn't deal directly with SFTP packet formats;
it implements the SFTP server logic in a more abstract way, by having
a vtable method for each SFTP request type with an appropriate
parameter list. It sends its replies by calling methods in another
vtable called SftpReplyBuilder, which in the normal case will write an
SFTP reply packet to send back to the client. So SftpServer can focus
more or less completely on the details of a particular filesystem API
- and hence, the implementation I've got lives in the unix source
directory, and works directly with file descriptors and struct stat
and the like.
(One purpose of this abstraction layer is that I may well want to
write a second dummy implementation, for test-suite purposes, with
completely controllable behaviour, and now I have a handy place to
plug it in in place of the live filesystem.)
In between sesschan's parsing of the byte stream into SFTP packets and
the SftpServer object, there's a layer in the new file sftpserver.c
which does the actual packet decoding and encoding: each request
packet is passed to that, which pulls the fields out of the request
packet and calls the appropriate method of SftpServer. It also
provides the default SftpReplyBuilder which makes the output packet.
I've moved some code out of the previous SFTP client implementation -
basic packet construction code, and in particular the BinarySink/
BinarySource marshalling fuinction for fxp_attrs - into sftpcommon.c,
so that the two directions can share as much as possible.
2018-10-20 21:10:32 +00:00
|
|
|
|
|
|
|
/* ----------------------------------------------------------------------
|
|
|
|
* Built-in SFTP subsystem.
|
|
|
|
*/
|
|
|
|
|
|
|
|
static int sftp_chan_send(Channel *chan, int is_stderr,
|
|
|
|
const void *data, int length)
|
|
|
|
{
|
|
|
|
sesschan *sess = container_of(chan, sesschan, chan);
|
|
|
|
|
|
|
|
bufchain_add(&sess->subsys_input, data, length);
|
|
|
|
|
|
|
|
while (bufchain_size(&sess->subsys_input) >= 4) {
|
|
|
|
char lenbuf[4];
|
|
|
|
unsigned pktlen;
|
|
|
|
struct sftp_packet *pkt, *reply;
|
|
|
|
|
|
|
|
bufchain_fetch(&sess->subsys_input, lenbuf, 4);
|
|
|
|
pktlen = GET_32BIT(lenbuf);
|
|
|
|
|
|
|
|
if (bufchain_size(&sess->subsys_input) - 4 < pktlen)
|
|
|
|
break; /* wait for more data */
|
|
|
|
|
|
|
|
bufchain_consume(&sess->subsys_input, 4);
|
|
|
|
pkt = sftp_recv_prepare(pktlen);
|
|
|
|
bufchain_fetch_consume(&sess->subsys_input, pkt->data, pktlen);
|
|
|
|
sftp_recv_finish(pkt);
|
|
|
|
reply = sftp_handle_request(sess->sftpsrv, pkt);
|
|
|
|
sftp_pkt_free(pkt);
|
|
|
|
|
|
|
|
sftp_send_prepare(reply);
|
|
|
|
sshfwd_write(sess->c, reply->data, reply->length);
|
|
|
|
sftp_pkt_free(reply);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void sftp_chan_send_eof(Channel *chan)
|
|
|
|
{
|
|
|
|
sesschan *sess = container_of(chan, sesschan, chan);
|
|
|
|
sshfwd_write_eof(sess->c);
|
|
|
|
}
|
|
|
|
|
|
|
|
static char *sftp_log_close_msg(Channel *chan)
|
|
|
|
{
|
|
|
|
return dupstr("Session channel (SFTP) closed");
|
|
|
|
}
|