1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-01-09 09:27:59 +00:00

Provide Uppity with a built-in old-style scp server.

Like the SFTP server, this is implemented in-process rather than by
invoking a separate scp server binary.

It also uses the internal SftpServer abstraction for access to the
server's filesystem, which means that when (or if) I implement an
alternative SftpServer implementing a dummy file system for test suite
purposes, this scp server should automatically start using it too.

As a bonus, the new scpserver.c contains a large comment documenting
my understanding of the SCP protocol, which I previously didn't have
even a de-facto or post-hoc spec for. I don't claim it's authoritative
- it's all reverse-engineered from my own code and observing other
implementations in action - but at least it'll make it easier to
refresh my own memory of what's going on the next time I need to do
something to either this code or PSCP.
This commit is contained in:
Simon Tatham 2018-10-20 11:19:17 +01:00
parent 18d7998008
commit 8a60fdaa57
4 changed files with 1515 additions and 1 deletions

2
Recipe
View File

@ -284,7 +284,7 @@ UXMISC = MISCNET UXMISCCOMMON uxproxy
SSHSERVER = SSHCOMMON sshserver settings be_none logging ssh2kex-server
+ ssh2userauth-server sshrsag sshprime ssh2connection-server
+ sesschan sftpcommon int64 sftpserver proxy cproxy ssh1login-server
+ ssh1connection-server
+ ssh1connection-server scpserver
# import.c and dependencies, for PuTTYgen-like utilities that have to
# load foreign key files.

1407
scpserver.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -42,6 +42,7 @@ typedef struct sesschan {
bufchain subsys_input;
SftpServer *sftpsrv;
ScpServer *scpsrv;
Channel chan;
} sesschan;
@ -123,6 +124,36 @@ static const struct ChannelVtable sftp_channelvt = {
chan_no_request_response,
};
static int scp_chan_send(Channel *chan, int is_stderr, const void *, int);
static void scp_chan_send_eof(Channel *chan);
static void scp_set_input_wanted(Channel *chan, int wanted);
static char *scp_log_close_msg(Channel *chan);
static const struct ChannelVtable scp_channelvt = {
sesschan_free,
chan_remotely_opened_confirmation,
chan_remotely_opened_failure,
scp_chan_send,
scp_chan_send_eof,
scp_set_input_wanted,
scp_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,
};
static void sesschan_eventlog(LogPolicy *lp, const char *event) {}
static void sesschan_logging_error(LogPolicy *lp, const char *event) {}
static int sesschan_askappend(
@ -264,6 +295,14 @@ int sesschan_run_command(Channel *chan, ptrlen command)
if (sess->backend)
return FALSE;
/* FIXME: make this possible to configure off */
if ((sess->scpsrv = scp_recognise_exec(sess->c, sess->sftpserver_vt,
command)) != NULL) {
sess->chan.vt = &scp_channelvt;
logevent(sess->parent_logctx, "Starting built-in SCP server");
return TRUE;
}
char *command_str = mkstr(command);
sesschan_start_backend(sess, command_str);
sfree(command_str);
@ -651,3 +690,31 @@ static char *sftp_log_close_msg(Channel *chan)
{
return dupstr("Session channel (SFTP) closed");
}
/* ----------------------------------------------------------------------
* Built-in SCP subsystem.
*/
static int scp_chan_send(Channel *chan, int is_stderr,
const void *data, int length)
{
sesschan *sess = container_of(chan, sesschan, chan);
return scp_send(sess->scpsrv, data, length);
}
static void scp_chan_send_eof(Channel *chan)
{
sesschan *sess = container_of(chan, sesschan, chan);
scp_eof(sess->scpsrv);
}
static char *scp_log_close_msg(Channel *chan)
{
return dupstr("Session channel (SCP) closed");
}
static void scp_set_input_wanted(Channel *chan, int wanted)
{
sesschan *sess = container_of(chan, sesschan, chan);
scp_throttle(sess->scpsrv, !wanted);
}

40
sftp.h
View File

@ -56,6 +56,8 @@
#define SFTP_PROTO_VERSION 3
#define PERMS_DIRECTORY 040000
/*
* External references. The sftp client module sftp.c expects to be
* able to get at these functions.
@ -477,3 +479,41 @@ struct DefaultSftpReplyBuilder {
*/
struct sftp_packet *sftp_handle_request(
SftpServer *srv, struct sftp_packet *request);
/* ----------------------------------------------------------------------
* Not exactly SFTP-related, but here's a system that implements an
* old-fashioned SCP server module, given an SftpServer vtable to use
* as its underlying filesystem access.
*/
typedef struct ScpServer ScpServer;
typedef struct ScpServerVtable ScpServerVtable;
struct ScpServer {
const struct ScpServerVtable *vt;
};
struct ScpServerVtable {
void (*free)(ScpServer *s);
int (*send)(ScpServer *s, const void *data, size_t length);
void (*throttle)(ScpServer *s, int throttled);
void (*eof)(ScpServer *s);
};
#define scp_free(s) ((s)->vt->free(s))
#define scp_send(s, data, len) ((s)->vt->send(s, data, len))
#define scp_throttle(s, th) ((s)->vt->throttle(s, th))
#define scp_eof(s) ((s)->vt->eof(s))
/*
* Create an ScpServer by calling this function, giving it the command
* you received from the SSH client to execute. If that command is
* recognised as an scp command, it will construct an ScpServer object
* and return it; otherwise, it will return NULL, and you should
* execute the command in whatever way you normally would.
*
* The ScpServer will generate output for the client by writing it to
* the provided SshChannel using sshfwd_write; you pass it input using
* the send method in its own vtable.
*/
ScpServer *scp_recognise_exec(
SshChannel *sc, const SftpServerVtable *sftpserver_vt, ptrlen command);