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:
parent
18d7998008
commit
8a60fdaa57
2
Recipe
2
Recipe
@ -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
1407
scpserver.c
Normal file
File diff suppressed because it is too large
Load Diff
67
sesschan.c
67
sesschan.c
@ -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
40
sftp.h
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user