1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-01-25 01:02:24 +00:00

Move some ssh.c declarations into header files.

ssh.c has been an unmanageably huge monolith of a source file for too
long, and it's finally time I started breaking it up into smaller
pieces. The first step is to move some declarations - basic types like
packets and packet queues, standard constants, enums, and the
coroutine system - into headers where other files can see them.
This commit is contained in:
Simon Tatham 2018-06-09 09:07:18 +01:00
parent 8b98fea4ae
commit ba7571291a
3 changed files with 183 additions and 166 deletions

180
ssh.c
View File

@ -15,6 +15,7 @@
#include "storage.h" #include "storage.h"
#include "marshal.h" #include "marshal.h"
#include "ssh.h" #include "ssh.h"
#include "sshcr.h"
#ifndef NO_GSSAPI #ifndef NO_GSSAPI
#include "sshgssc.h" #include "sshgssc.h"
#include "sshgss.h" #include "sshgss.h"
@ -25,26 +26,6 @@
#define GSS_CTXT_MAYFAIL (1<<3) /* Context may expire during handshake */ #define GSS_CTXT_MAYFAIL (1<<3) /* Context may expire during handshake */
#endif #endif
/*
* Packet type contexts, so that ssh2_pkt_type can correctly decode
* the ambiguous type numbers back into the correct type strings.
*/
typedef enum {
SSH2_PKTCTX_NOKEX,
SSH2_PKTCTX_DHGROUP,
SSH2_PKTCTX_DHGEX,
SSH2_PKTCTX_ECDHKEX,
SSH2_PKTCTX_GSSKEX,
SSH2_PKTCTX_RSAKEX
} Pkt_KCtx;
typedef enum {
SSH2_PKTCTX_NOAUTH,
SSH2_PKTCTX_PUBLICKEY,
SSH2_PKTCTX_PASSWORD,
SSH2_PKTCTX_GSSAPI,
SSH2_PKTCTX_KBDINTER
} Pkt_ACtx;
static const char *const ssh2_disconnect_reasons[] = { static const char *const ssh2_disconnect_reasons[] = {
NULL, NULL,
"host not allowed to connect", "host not allowed to connect",
@ -200,7 +181,7 @@ static unsigned long rekey_mins(int rekey_time, unsigned long def)
#define translate(x) if (type == x) return #x #define translate(x) if (type == x) return #x
#define translatek(x,ctx) if (type == x && (pkt_kctx == ctx)) return #x #define translatek(x,ctx) if (type == x && (pkt_kctx == ctx)) return #x
#define translatea(x,ctx) if (type == x && (pkt_actx == ctx)) return #x #define translatea(x,ctx) if (type == x && (pkt_actx == ctx)) return #x
static const char *ssh1_pkt_type(int type) const char *ssh1_pkt_type(int type)
{ {
translate(SSH1_MSG_DISCONNECT); translate(SSH1_MSG_DISCONNECT);
translate(SSH1_SMSG_PUBLIC_KEY); translate(SSH1_SMSG_PUBLIC_KEY);
@ -245,8 +226,7 @@ static const char *ssh1_pkt_type(int type)
translate(SSH1_CMSG_AUTH_CCARD_RESPONSE); translate(SSH1_CMSG_AUTH_CCARD_RESPONSE);
return "unknown"; return "unknown";
} }
static const char *ssh2_pkt_type(Pkt_KCtx pkt_kctx, Pkt_ACtx pkt_actx, const char *ssh2_pkt_type(Pkt_KCtx pkt_kctx, Pkt_ACtx pkt_actx, int type)
int type)
{ {
translatea(SSH2_MSG_USERAUTH_GSSAPI_RESPONSE,SSH2_PKTCTX_GSSAPI); translatea(SSH2_MSG_USERAUTH_GSSAPI_RESPONSE,SSH2_PKTCTX_GSSAPI);
translatea(SSH2_MSG_USERAUTH_GSSAPI_TOKEN,SSH2_PKTCTX_GSSAPI); translatea(SSH2_MSG_USERAUTH_GSSAPI_TOKEN,SSH2_PKTCTX_GSSAPI);
@ -313,57 +293,6 @@ enum {
PKT_END, PKT_INT, PKT_CHAR, PKT_DATA, PKT_STR, PKT_BIGNUM, PKT_END, PKT_INT, PKT_CHAR, PKT_DATA, PKT_STR, PKT_BIGNUM,
}; };
/*
* Coroutine mechanics for the sillier bits of the code. If these
* macros look impenetrable to you, you might find it helpful to
* read
*
* https://www.chiark.greenend.org.uk/~sgtatham/coroutines.html
*
* which explains the theory behind these macros.
*
* In particular, if you are getting `case expression not constant'
* errors when building with MS Visual Studio, this is because MS's
* Edit and Continue debugging feature causes their compiler to
* violate ANSI C. To disable Edit and Continue debugging:
*
* - right-click ssh.c in the FileView
* - click Settings
* - select the C/C++ tab and the General category
* - under `Debug info:', select anything _other_ than `Program
* Database for Edit and Continue'.
*/
#define crBegin(v) { int *crLine = &v; switch(v) { case 0:;
#define crBeginState crBegin(s->crLine)
#define crStateP(t, v) \
struct t *s; \
if (!(v)) { s = (v) = snew(struct t); s->crLine = 0; } \
s = (v);
#define crState(t) crStateP(t, ssh->t)
#define crFinish(z) } *crLine = 0; return (z); }
#define crFinishV } *crLine = 0; return; }
#define crFinishFree(z) } sfree(s); return (z); }
#define crFinishFreeV } sfree(s); return; }
#define crReturn(z) \
do {\
*crLine =__LINE__; return (z); case __LINE__:;\
} while (0)
#define crReturnV \
do {\
*crLine=__LINE__; return; case __LINE__:;\
} while (0)
#define crStop(z) do{ *crLine = 0; return (z); }while(0)
#define crStopV do{ *crLine = 0; return; }while(0)
#define crWaitUntil(c) do { crReturn(0); } while (!(c))
#define crWaitUntilV(c) do { crReturnV; } while (!(c))
#define crMaybeWaitUntil(c) do { while (!(c)) crReturn(0); } while (0)
#define crMaybeWaitUntilV(c) do { while (!(c)) crReturnV; } while (0)
typedef struct PktIn PktIn;
typedef struct PktOut PktOut;
static struct PktOut *ssh1_pkt_init(int pkt_type);
static struct PktOut *ssh2_pkt_init(int pkt_type);
static void ssh_pkt_ensure(struct PktOut *, int length); static void ssh_pkt_ensure(struct PktOut *, int length);
static void ssh_pkt_adddata(struct PktOut *, const void *data, int len); static void ssh_pkt_adddata(struct PktOut *, const void *data, int len);
static ptrlen ssh2_pkt_construct(Ssh, struct PktOut *); static ptrlen ssh2_pkt_construct(Ssh, struct PktOut *);
@ -386,47 +315,6 @@ static void ssh1_login_input(Ssh ssh);
static void ssh2_userauth_input(Ssh ssh); static void ssh2_userauth_input(Ssh ssh);
static void ssh2_connection_input(Ssh ssh); static void ssh2_connection_input(Ssh ssh);
/*
* Buffer management constants. There are several of these for
* various different purposes:
*
* - SSH1_BUFFER_LIMIT is the amount of backlog that must build up
* on a local data stream before we throttle the whole SSH
* connection (in SSH-1 only). Throttling the whole connection is
* pretty drastic so we set this high in the hope it won't
* happen very often.
*
* - SSH_MAX_BACKLOG is the amount of backlog that must build up
* on the SSH connection itself before we defensively throttle
* _all_ local data streams. This is pretty drastic too (though
* thankfully unlikely in SSH-2 since the window mechanism should
* ensure that the server never has any need to throttle its end
* of the connection), so we set this high as well.
*
* - OUR_V2_WINSIZE is the default window size we present on SSH-2
* channels.
*
* - OUR_V2_BIGWIN is the window size we advertise for the only
* channel in a simple connection. It must be <= INT_MAX.
*
* - OUR_V2_MAXPKT is the official "maximum packet size" we send
* to the remote side. This actually has nothing to do with the
* size of the _packet_, but is instead a limit on the amount
* of data we're willing to receive in a single SSH2 channel
* data message.
*
* - OUR_V2_PACKETLIMIT is actually the maximum size of SSH
* _packet_ we're prepared to cope with. It must be a multiple
* of the cipher block size, and must be at least 35000.
*/
#define SSH1_BUFFER_LIMIT 32768
#define SSH_MAX_BACKLOG 32768
#define OUR_V2_WINSIZE 16384
#define OUR_V2_BIGWIN 0x7fffffff
#define OUR_V2_MAXPKT 0x4000UL
#define OUR_V2_PACKETLIMIT 0x9000UL
struct ssh_signkey_with_user_pref_id { struct ssh_signkey_with_user_pref_id {
const ssh_keyalg *alg; const ssh_keyalg *alg;
int id; int id;
@ -670,40 +558,6 @@ struct ssh_portfwd {
((pf) ? (sfree((pf)->saddr), sfree((pf)->daddr), \ ((pf) ? (sfree((pf)->saddr), sfree((pf)->daddr), \
sfree((pf)->sserv), sfree((pf)->dserv)) : (void)0 ), sfree(pf) ) sfree((pf)->sserv), sfree((pf)->dserv)) : (void)0 ), sfree(pf) )
typedef struct PacketQueueNode PacketQueueNode;
struct PacketQueueNode {
PacketQueueNode *next, *prev;
};
struct PktIn {
int refcount;
int type;
unsigned long sequence; /* SSH-2 incoming sequence number */
long encrypted_len; /* for SSH-2 total-size counting */
PacketQueueNode qnode; /* for linking this packet on to a queue */
BinarySource_IMPLEMENTATION;
};
struct PktOut {
long prefix; /* bytes up to and including type field */
long length; /* total bytes, including prefix */
int type;
long forcepad; /* SSH-2: force padding to at least this length */
unsigned char *data; /* allocated storage */
long maxlen; /* amount of storage allocated for `data' */
long encrypted_len; /* for SSH-2 total-size counting */
/* Extra metadata used in SSH packet logging mode, allowing us to
* log in the packet header line that the packet came from a
* connection-sharing downstream and what if anything unusual was
* done to it. The additional_log_text field is expected to be a
* static string - it will not be freed. */
unsigned downstream_id;
const char *additional_log_text;
BinarySink_IMPLEMENTATION;
};
static void ssh1_protocol_setup(Ssh ssh); static void ssh1_protocol_setup(Ssh ssh);
static void ssh2_protocol_setup(Ssh ssh); static void ssh2_protocol_setup(Ssh ssh);
static void ssh2_bare_connection_protocol_setup(Ssh ssh); static void ssh2_bare_connection_protocol_setup(Ssh ssh);
@ -724,18 +578,13 @@ static PktOut *ssh2_gss_authpacket(Ssh ssh, Ssh_gss_ctx gss_ctx,
const char *authtype); const char *authtype);
#endif #endif
static void ssh2_msg_unexpected(Ssh ssh, PktIn *pktin); static void ssh2_msg_unexpected(Ssh ssh, PktIn *pktin);
static void ssh_unref_packet(PktIn *pkt);
struct PacketQueue { void pq_init(struct PacketQueue *pq)
PacketQueueNode end;
};
static void pq_init(struct PacketQueue *pq)
{ {
pq->end.next = pq->end.prev = &pq->end; pq->end.next = pq->end.prev = &pq->end;
} }
static void pq_push(struct PacketQueue *pq, PktIn *pkt) void pq_push(struct PacketQueue *pq, PktIn *pkt)
{ {
PacketQueueNode *node = &pkt->qnode; PacketQueueNode *node = &pkt->qnode;
assert(!node->next); assert(!node->next);
@ -746,7 +595,7 @@ static void pq_push(struct PacketQueue *pq, PktIn *pkt)
node->prev->next = node; node->prev->next = node;
} }
static void pq_push_front(struct PacketQueue *pq, PktIn *pkt) void pq_push_front(struct PacketQueue *pq, PktIn *pkt)
{ {
PacketQueueNode *node = &pkt->qnode; PacketQueueNode *node = &pkt->qnode;
assert(!node->next); assert(!node->next);
@ -757,14 +606,14 @@ static void pq_push_front(struct PacketQueue *pq, PktIn *pkt)
node->prev->next = node; node->prev->next = node;
} }
static PktIn *pq_peek(struct PacketQueue *pq) PktIn *pq_peek(struct PacketQueue *pq)
{ {
if (pq->end.next == &pq->end) if (pq->end.next == &pq->end)
return NULL; return NULL;
return FROMFIELD(pq->end.next, PktIn, qnode); return FROMFIELD(pq->end.next, PktIn, qnode);
} }
static PktIn *pq_pop(struct PacketQueue *pq) PktIn *pq_pop(struct PacketQueue *pq)
{ {
PacketQueueNode *node = pq->end.next; PacketQueueNode *node = pq->end.next;
if (node == &pq->end) if (node == &pq->end)
@ -777,15 +626,14 @@ static PktIn *pq_pop(struct PacketQueue *pq)
return FROMFIELD(node, PktIn, qnode); return FROMFIELD(node, PktIn, qnode);
} }
static void pq_clear(struct PacketQueue *pq) void pq_clear(struct PacketQueue *pq)
{ {
PktIn *pkt; PktIn *pkt;
while ((pkt = pq_pop(pq)) != NULL) while ((pkt = pq_pop(pq)) != NULL)
ssh_unref_packet(pkt); ssh_unref_packet(pkt);
} }
static int pq_empty_on_to_front_of(struct PacketQueue *src, int pq_empty_on_to_front_of(struct PacketQueue *src, struct PacketQueue *dest)
struct PacketQueue *dest)
{ {
struct PacketQueueNode *srcfirst, *srclast; struct PacketQueueNode *srcfirst, *srclast;
@ -1373,13 +1221,13 @@ static void c_write_str(Ssh ssh, const char *buf)
c_write(ssh, buf, strlen(buf)); c_write(ssh, buf, strlen(buf));
} }
static void ssh_unref_packet(PktIn *pkt) void ssh_unref_packet(PktIn *pkt)
{ {
if (--pkt->refcount <= 0) if (--pkt->refcount <= 0)
sfree(pkt); sfree(pkt);
} }
static void ssh_free_pktout(PktOut *pkt) void ssh_free_pktout(PktOut *pkt)
{ {
sfree(pkt->data); sfree(pkt->data);
sfree(pkt); sfree(pkt);
@ -2347,7 +2195,7 @@ static void ssh_pkt_BinarySink_write(BinarySink *bs,
ssh_pkt_adddata(pkt, data, len); ssh_pkt_adddata(pkt, data, len);
} }
static PktOut *ssh1_pkt_init(int pkt_type) PktOut *ssh1_pkt_init(int pkt_type)
{ {
PktOut *pkt = ssh_new_packet(); PktOut *pkt = ssh_new_packet();
pkt->length = 4 + 8; /* space for length + max padding */ pkt->length = 4 + 8; /* space for length + max padding */
@ -2359,7 +2207,7 @@ static PktOut *ssh1_pkt_init(int pkt_type)
return pkt; return pkt;
} }
static PktOut *ssh2_pkt_init(int pkt_type) PktOut *ssh2_pkt_init(int pkt_type)
{ {
PktOut *pkt = ssh_new_packet(); PktOut *pkt = ssh_new_packet();
pkt->length = 5; /* space for packet length + padding length */ pkt->length = 5; /* space for packet length + padding length */

115
ssh.h
View File

@ -22,6 +22,118 @@ void sshfwd_x11_sharing_handover(struct ssh_channel *c,
const void *initial_data, int initial_len); const void *initial_data, int initial_len);
void sshfwd_x11_is_local(struct ssh_channel *c); void sshfwd_x11_is_local(struct ssh_channel *c);
/*
* Buffer management constants. There are several of these for
* various different purposes:
*
* - SSH1_BUFFER_LIMIT is the amount of backlog that must build up
* on a local data stream before we throttle the whole SSH
* connection (in SSH-1 only). Throttling the whole connection is
* pretty drastic so we set this high in the hope it won't
* happen very often.
*
* - SSH_MAX_BACKLOG is the amount of backlog that must build up
* on the SSH connection itself before we defensively throttle
* _all_ local data streams. This is pretty drastic too (though
* thankfully unlikely in SSH-2 since the window mechanism should
* ensure that the server never has any need to throttle its end
* of the connection), so we set this high as well.
*
* - OUR_V2_WINSIZE is the default window size we present on SSH-2
* channels.
*
* - OUR_V2_BIGWIN is the window size we advertise for the only
* channel in a simple connection. It must be <= INT_MAX.
*
* - OUR_V2_MAXPKT is the official "maximum packet size" we send
* to the remote side. This actually has nothing to do with the
* size of the _packet_, but is instead a limit on the amount
* of data we're willing to receive in a single SSH2 channel
* data message.
*
* - OUR_V2_PACKETLIMIT is actually the maximum size of SSH
* _packet_ we're prepared to cope with. It must be a multiple
* of the cipher block size, and must be at least 35000.
*/
#define SSH1_BUFFER_LIMIT 32768
#define SSH_MAX_BACKLOG 32768
#define OUR_V2_WINSIZE 16384
#define OUR_V2_BIGWIN 0x7fffffff
#define OUR_V2_MAXPKT 0x4000UL
#define OUR_V2_PACKETLIMIT 0x9000UL
typedef struct PacketQueueNode PacketQueueNode;
struct PacketQueueNode {
PacketQueueNode *next, *prev;
};
typedef struct PktIn {
int refcount;
int type;
unsigned long sequence; /* SSH-2 incoming sequence number */
long encrypted_len; /* for SSH-2 total-size counting */
PacketQueueNode qnode; /* for linking this packet on to a queue */
BinarySource_IMPLEMENTATION;
} PktIn;
typedef struct PktOut {
long prefix; /* bytes up to and including type field */
long length; /* total bytes, including prefix */
int type;
long forcepad; /* SSH-2: force padding to at least this length */
unsigned char *data; /* allocated storage */
long maxlen; /* amount of storage allocated for `data' */
long encrypted_len; /* for SSH-2 total-size counting */
/* Extra metadata used in SSH packet logging mode, allowing us to
* log in the packet header line that the packet came from a
* connection-sharing downstream and what if anything unusual was
* done to it. The additional_log_text field is expected to be a
* static string - it will not be freed. */
unsigned downstream_id;
const char *additional_log_text;
BinarySink_IMPLEMENTATION;
} PktOut;
typedef struct PacketQueue {
PacketQueueNode end;
} PacketQueue;
void pq_init(struct PacketQueue *pq);
void pq_push(struct PacketQueue *pq, PktIn *pkt);
void pq_push_front(struct PacketQueue *pq, PktIn *pkt);
PktIn *pq_peek(struct PacketQueue *pq);
PktIn *pq_pop(struct PacketQueue *pq);
void pq_clear(struct PacketQueue *pq);
int pq_empty_on_to_front_of(struct PacketQueue *src, struct PacketQueue *dest);
/*
* Packet type contexts, so that ssh2_pkt_type can correctly decode
* the ambiguous type numbers back into the correct type strings.
*/
typedef enum {
SSH2_PKTCTX_NOKEX,
SSH2_PKTCTX_DHGROUP,
SSH2_PKTCTX_DHGEX,
SSH2_PKTCTX_ECDHKEX,
SSH2_PKTCTX_GSSKEX,
SSH2_PKTCTX_RSAKEX
} Pkt_KCtx;
typedef enum {
SSH2_PKTCTX_NOAUTH,
SSH2_PKTCTX_PUBLICKEY,
SSH2_PKTCTX_PASSWORD,
SSH2_PKTCTX_GSSAPI,
SSH2_PKTCTX_KBDINTER
} Pkt_ACtx;
PktOut *ssh1_pkt_init(int pkt_type);
PktOut *ssh2_pkt_init(int pkt_type);
void ssh_unref_packet(PktIn *pkt);
void ssh_free_pktout(PktOut *pkt);
extern Socket ssh_connection_sharing_init( extern Socket ssh_connection_sharing_init(
const char *host, int port, Conf *conf, Ssh ssh, Plug sshplug, const char *host, int port, Conf *conf, Ssh ssh, Plug sshplug,
void **state); void **state);
@ -1048,6 +1160,9 @@ void platform_ssh_share_cleanup(const char *name);
#define SSH2_EXTENDED_DATA_STDERR 1 /* 0x1 */ #define SSH2_EXTENDED_DATA_STDERR 1 /* 0x1 */
const char *ssh1_pkt_type(int type);
const char *ssh2_pkt_type(Pkt_KCtx pkt_kctx, Pkt_ACtx pkt_actx, int type);
/* /*
* Need this to warn about support for the original SSH-2 keyfile * Need this to warn about support for the original SSH-2 keyfile
* format. * format.

54
sshcr.h Normal file
View File

@ -0,0 +1,54 @@
/*
* Coroutine mechanics used in PuTTY's SSH code.
*/
#ifndef PUTTY_SSHCR_H
#define PUTTY_SSHCR_H
/*
* If these macros look impenetrable to you, you might find it helpful
* to read
*
* https://www.chiark.greenend.org.uk/~sgtatham/coroutines.html
*
* which explains the theory behind these macros.
*
* In particular, if you are getting `case expression not constant'
* errors when building with MS Visual Studio, this is because MS's
* Edit and Continue debugging feature causes their compiler to
* violate ANSI C. To disable Edit and Continue debugging:
*
* - right-click ssh.c in the FileView
* - click Settings
* - select the C/C++ tab and the General category
* - under `Debug info:', select anything _other_ than `Program
* Database for Edit and Continue'.
*/
#define crBegin(v) { int *crLine = &v; switch(v) { case 0:;
#define crBeginState crBegin(s->crLine)
#define crStateP(t, v) \
struct t *s; \
if (!(v)) { s = (v) = snew(struct t); s->crLine = 0; } \
s = (v);
#define crState(t) crStateP(t, ssh->t)
#define crFinish(z) } *crLine = 0; return (z); }
#define crFinishV } *crLine = 0; return; }
#define crFinishFree(z) } sfree(s); return (z); }
#define crFinishFreeV } sfree(s); return; }
#define crReturn(z) \
do {\
*crLine =__LINE__; return (z); case __LINE__:;\
} while (0)
#define crReturnV \
do {\
*crLine=__LINE__; return; case __LINE__:;\
} while (0)
#define crStop(z) do{ *crLine = 0; return (z); }while(0)
#define crStopV do{ *crLine = 0; return; }while(0)
#define crWaitUntil(c) do { crReturn(0); } while (!(c))
#define crWaitUntilV(c) do { crReturnV; } while (!(c))
#define crMaybeWaitUntil(c) do { while (!(c)) crReturn(0); } while (0)
#define crMaybeWaitUntilV(c) do { while (!(c)) crReturnV; } while (0)
#endif /* PUTTY_SSHCR_H */