1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-01-09 17:38:00 +00:00
putty-source/sshppl.h
Simon Tatham 1d323d5c80 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-21 10:02:10 +01:00

155 lines
6.4 KiB
C

/*
* Abstraction of the various layers of SSH packet-level protocol,
* general enough to take in all three of the main SSH-2 layers and
* both of the SSH-1 phases.
*/
#ifndef PUTTY_SSHPPL_H
#define PUTTY_SSHPPL_H
typedef void (*packet_handler_fn_t)(PacketProtocolLayer *ppl, PktIn *pktin);
struct PacketProtocolLayerVtable {
void (*free)(PacketProtocolLayer *);
void (*process_queue)(PacketProtocolLayer *ppl);
int (*get_specials)(
PacketProtocolLayer *ppl, add_special_fn_t add_special, void *ctx);
void (*special_cmd)(
PacketProtocolLayer *ppl, SessionSpecialCode code, int arg);
int (*want_user_input)(PacketProtocolLayer *ppl);
void (*got_user_input)(PacketProtocolLayer *ppl);
void (*reconfigure)(PacketProtocolLayer *ppl, Conf *conf);
/* Protocol-level name of this layer. */
const char *name;
};
struct PacketProtocolLayer {
const struct PacketProtocolLayerVtable *vt;
/* Link to the underlying SSH BPP. */
BinaryPacketProtocol *bpp;
/* Queue from which the layer receives its input packets, and one
* to put its output packets on. */
PktInQueue *in_pq;
PktOutQueue *out_pq;
/* Idempotent callback that in_pq will be linked to, causing a
* call to the process_queue method. in_pq points to this, so it
* will be automatically triggered by pushing things on the
* layer's input queue, but it can also be triggered on purpose. */
IdempotentCallback ic_process_queue;
/* Owner's pointer to this layer. Permits a layer to unilaterally
* abdicate in favour of a replacement, by overwriting this
* pointer and then freeing itself. */
PacketProtocolLayer **selfptr;
/* Bufchain of keyboard input from the user, for login prompts and
* similar. */
bufchain *user_input;
/* Logging and error-reporting facilities. */
LogContext *logctx;
Seat *seat; /* for dialog boxes, session output etc */
Ssh *ssh; /* for session termination + assorted connection-layer ops */
/* Known bugs in the remote implementation. */
unsigned remote_bugs;
};
#define ssh_ppl_process_queue(ppl) ((ppl)->vt->process_queue(ppl))
#define ssh_ppl_get_specials(ppl, add, ctx) \
((ppl)->vt->get_specials(ppl, add, ctx))
#define ssh_ppl_special_cmd(ppl, code, arg) \
((ppl)->vt->special_cmd(ppl, code, arg))
#define ssh_ppl_want_user_input(ppl) ((ppl)->vt->want_user_input(ppl))
#define ssh_ppl_got_user_input(ppl) ((ppl)->vt->got_user_input(ppl))
#define ssh_ppl_reconfigure(ppl, conf) ((ppl)->vt->reconfigure(ppl, conf))
/* ssh_ppl_free is more than just a macro wrapper on the vtable; it
* does centralised parts of the freeing too. */
void ssh_ppl_free(PacketProtocolLayer *ppl);
/* Helper routine to point a PPL at its input and output queues. Also
* sets up the IdempotentCallback on the input queue to trigger a call
* to process_queue whenever packets are added to it. */
void ssh_ppl_setup_queues(PacketProtocolLayer *ppl,
PktInQueue *inq, PktOutQueue *outq);
/* Routine a PPL can call to abdicate in favour of a replacement, by
* overwriting ppl->selfptr. Has the side effect of freeing 'old', so
* if 'old' actually called this (which is likely) then it should
* avoid dereferencing itself on return from this function! */
void ssh_ppl_replace(PacketProtocolLayer *old, PacketProtocolLayer *new);
PacketProtocolLayer *ssh1_login_new(
Conf *conf, const char *host, int port,
PacketProtocolLayer *successor_layer);
PacketProtocolLayer *ssh1_connection_new(
Ssh *ssh, Conf *conf, ConnectionLayer **cl_out);
struct DataTransferStats;
struct ssh_connection_shared_gss_state;
PacketProtocolLayer *ssh2_transport_new(
Conf *conf, const char *host, int port, const char *fullhostname,
const char *client_greeting, const char *server_greeting,
struct ssh_connection_shared_gss_state *shgss,
struct DataTransferStats *stats, PacketProtocolLayer *higher_layer,
int is_server);
PacketProtocolLayer *ssh2_userauth_new(
PacketProtocolLayer *successor_layer,
const char *hostname, const char *fullhostname,
Filename *keyfile, int tryagent,
const char *default_username, int change_username,
int try_ki_auth,
int try_gssapi_auth, int try_gssapi_kex_auth,
int gssapi_fwd, struct ssh_connection_shared_gss_state *shgss);
PacketProtocolLayer *ssh2_connection_new(
Ssh *ssh, ssh_sharing_state *connshare, int is_simple,
Conf *conf, const char *peer_verstring, ConnectionLayer **cl_out);
/* Can't put this in the userauth constructor without having a
* dependency loop at setup time (transport and userauth can't _both_
* be constructed second and given a pointer to the other). */
void ssh2_userauth_set_transport_layer(PacketProtocolLayer *userauth,
PacketProtocolLayer *transport);
/* Convenience macro for protocol layers to send formatted strings to
* the Event Log. Assumes a function parameter called 'ppl' is in
* scope, and takes a double pair of parens because it passes a whole
* argument list to dupprintf. */
#define ppl_logevent(params) ( \
logevent_and_free((ppl)->logctx, dupprintf params))
/* Convenience macro for protocol layers to send formatted strings to
* the terminal. Also expects 'ppl' to be in scope and takes double
* parens. */
#define ppl_printf(params) \
ssh_ppl_user_output_string_and_free(ppl, dupprintf params)
void ssh_ppl_user_output_string_and_free(PacketProtocolLayer *ppl, char *text);
/* Methods for userauth to communicate back to the transport layer */
ptrlen ssh2_transport_get_session_id(PacketProtocolLayer *ssh2_transport_ptr);
void ssh2_transport_notify_auth_done(PacketProtocolLayer *ssh2_transport_ptr);
/* Methods for ssh1login to pass protocol flags to ssh1connection */
void ssh1_connection_set_protoflags(
PacketProtocolLayer *ppl, int local, int remote);
/* Shared get_specials method between the two ssh1 layers */
int ssh1_common_get_specials(PacketProtocolLayer *, add_special_fn_t, void *);
/* Other shared functions between ssh1 layers */
int ssh1_common_filter_queue(PacketProtocolLayer *ppl);
void ssh1_compute_session_id(
unsigned char *session_id, const unsigned char *cookie,
struct RSAKey *hostkey, struct RSAKey *servkey);
/* Method used by the SSH server */
void ssh2_transport_provide_hostkeys(PacketProtocolLayer *ssh2_transport_ptr,
ssh_key *const *hostkeys, int nhostkeys);
#endif /* PUTTY_SSHPPL_H */