#include <bio.h>
#define MYID "SSH-2.0-Plan9"
#pragma varargck type "M" mpint*
enum {
CONNSHIFT = 10,
MAXCONN = 1 << CONNSHIFT,
LEVSHIFT = 2 * CONNSHIFT + 3,
RootFile = 0,
CloneFile = 1 << (2 * CONNSHIFT),
CtlFile = 2 << (2 * CONNSHIFT),
DataFile = 3 << (2 * CONNSHIFT),
ListenFile = 4 << (2 * CONNSHIFT),
LocalFile = 5 << (2 * CONNSHIFT),
ReqRemFile = 6 << (2 * CONNSHIFT),
StatusFile = 7 << (2* CONNSHIFT),
FileMask = 7 << (2 * CONNSHIFT),
ConnMask = (1 << CONNSHIFT) - 1,
Server = 0,
Client,
};
/*
* The stylistic anomaly with these names of unbounded length
* is a result of following the RFCs in using the same names for
* these constants. I did that to make it easier to search and
* cross-reference between the code and the RFCs.
*/
enum /* SSH2 Protocol Packet Types */
{
SSH_MSG_DISCONNECT = 1,
SSH_MSG_IGNORE = 2,
SSH_MSG_UNIMPLEMENTED,
SSH_MSG_DEBUG,
SSH_MSG_SERVICE_REQUEST,
SSH_MSG_SERVICE_ACCEPT,
SSH_MSG_KEXINIT = 20,
SSH_MSG_NEWKEYS,
SSH_MSG_KEXDH_INIT = 30,
SSH_MSG_KEXDH_REPLY,
SSH_MSG_USERAUTH_REQUEST = 50,
SSH_MSG_USERAUTH_FAILURE,
SSH_MSG_USERAUTH_SUCCESS,
SSH_MSG_USERAUTH_BANNER,
SSH_MSG_USERAUTH_PK_OK = 60,
SSH_MSG_USERAUTH_PASSWD_CHANGEREQ = 60,
SSH_MSG_GLOBAL_REQUEST = 80,
SSH_MSG_REQUEST_SUCCESS,
SSH_MSG_REQUEST_FAILURE,
SSH_MSG_CHANNEL_OPEN = 90,
SSH_MSG_CHANNEL_OPEN_CONFIRMATION,
SSH_MSG_CHANNEL_OPEN_FAILURE,
SSH_MSG_CHANNEL_WINDOW_ADJUST,
SSH_MSG_CHANNEL_DATA,
SSH_MSG_CHANNEL_EXTENDED_DATA,
SSH_MSG_CHANNEL_EOF,
SSH_MSG_CHANNEL_CLOSE,
SSH_MSG_CHANNEL_REQUEST,
SSH_MSG_CHANNEL_SUCCESS,
SSH_MSG_CHANNEL_FAILURE,
};
enum /* SSH2 reason codes */
{
SSH_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT = 1,
SSH_DISCONNECT_PROTOCOL_ERROR,
SSH_DISCONNECT_KEY_EXCHANGE_FAILED,
SSH_DISCONNECT_RESERVED,
SSH_DISCONNECT_MAC_ERROR,
SSH_DISCONNECT_COMPRESSION_ERROR,
SSH_DISCONNECT_SERVICE_NOT_AVAILABLE,
SSH_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED,
SSH_DISCONNECT_HOST_KEY_NOT_VERIFIABLE,
SSH_DISCONNECT_CONNECTION_LOST,
SSH_DISCONNECT_BY_APPLICATION,
SSH_DISCONNECT_TOO_MANY_CONNECTIONS,
SSH_DISCONNECT_AUTH_CANCELLED_BY_USER,
SSH_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE,
SSH_DISCONNECT_ILLEGAL_USR_NAME,
SSH_OPEN_ADMINISTRATIVELY_PROHIBITED = 1,
SSH_OPEN_CONNECT_FAILED,
SSH_OPEN_UNKNOWN_CHANNEL_TYPE,
SSH_OPEN_RESOURCE_SHORTAGE,
};
enum /* SSH2 type code */
{
SSH_EXTENDED_DATA_STDERR = 1,
};
enum /* connection and channel states */
{
Empty = 0,
Allocated,
Initting,
Listening,
Opening,
Negotiating,
Authing,
Established,
Eof,
Closing,
Closed,
};
enum {
NoKeyFile,
NoKey,
KeyWrong,
KeyOk,
};
typedef struct Plist Plist;
typedef struct SSHChan SSHChan;
typedef struct Conn Conn;
typedef struct Packet Packet;
typedef struct Cipher Cipher;
typedef struct CipherState CipherState;
typedef struct Kex Kex;
typedef struct PKA PKA;
typedef struct MBox MBox;
#pragma incomplete CipherState
struct Plist {
Packet *pack;
uchar *st;
int rem;
Plist *next;
};
struct SSHChan {
Rendez r;
int id, otherid, state;
int waker;
int conn;
ulong rwindow, twindow;
ulong sent, inrqueue;
char *ann;
Req *lreq;
File *dir, *ctl, *data, *listen, *request, *status;
Plist *dataq, *datatl, *reqq, *reqtl;
Channel *inchan, *reqchan;
QLock xmtlock;
Rendez xmtrendez;
};
struct Conn {
QLock l;
Rendez r;
Ioproc *dio, *cio, *rio;
int state;
int role;
int id;
char *remote;
char *user, *password, *service;
char *cap;
char *authkey;
int nchan;
int datafd, ctlfd;
int rpid;
int inseq, outseq;
int kexalg, pkalg;
int cscrypt, ncscrypt, sccrypt, nsccrypt, csmac, ncsmac, scmac, nscmac;
int encrypt, decrypt, outmac, inmac;
File *dir, *clonefile, *ctlfile, *datafile, *listenfile, *localfile, *remotefile, *statusfile;
Packet *skexinit, *rkexinit;
mpint *x, *e;
int got_sessid;
uchar sessid[SHA1dlen];
uchar c2siv[SHA1dlen*2], nc2siv[SHA1dlen*2], s2civ[SHA1dlen*2], ns2civ[SHA1dlen*2];
uchar c2sek[SHA1dlen*2], nc2sek[SHA1dlen*2], s2cek[SHA1dlen*2], ns2cek[SHA1dlen*2];
uchar c2sik[SHA1dlen*2], nc2sik[SHA1dlen*2], s2cik[SHA1dlen*2], ns2cik[SHA1dlen*2];
char *otherid;
uchar *inik, *outik;
CipherState *s2ccs, *c2scs;
CipherState *enccs, *deccs;
SSHChan *chans[MAXCONN];
};
struct Packet {
Conn *c;
ulong rlength, tlength;
uchar nlength[4];
uchar pad_len;
uchar payload[35000];
};
struct Cipher
{
char *name;
int blklen;
CipherState *(*init)(Conn*, int);
void (*encrypt)(CipherState*, uchar*, int);
void (*decrypt)(CipherState*, uchar*, int);
};
struct Kex
{
char *name;
int (*serverkex)(Conn *, Packet *);
int (*clientkex1)(Conn *, Packet *);
int (*clientkex2)(Conn *, Packet *);
};
struct PKA
{
char *name;
Packet *(*ks)(Conn *);
Packet *(*sign)(Conn *, uchar *, int);
int (*verify)(Conn *, uchar *, int, char *, char *, int);
};
struct MBox
{
Channel *mchan;
char *msg;
int state;
};
extern int debug;
extern Cipher cipherblowfish, cipher3des, cipherrc4;
extern Cipher cipheraes128, cipheraes192, cipheraes256;
extern Kex dh1sha1, dh14sha1;
extern PKA rsa_pka, dss_pka, *pkas[];
extern sshkeychan[];
extern MBox keymbox;
/* pubkey.c */
RSApub *readpublickey(Biobuf *, char **);
int findkey(char *, char *, RSApub *);
int replacekey(char *, char *, RSApub *);
int appendkey(char *, char *, RSApub *);
/* dh.c */
void dh_init(PKA *[]);
/* transport.c */
Packet *new_packet(Conn *);
void init_packet(Packet *);
void add_byte(Packet *, char);
void add_uint32(Packet *, ulong);
ulong get_uint32(Packet *, uchar **);
int add_packet(Packet *, void *, int);
void add_block(Packet *, void *, int);
void add_string(Packet *, char *);
uchar *get_string(Packet *, uchar *, char *, int, int *);
void add_mp(Packet *, mpint *);
mpint *get_mp(uchar *q);
int finish_packet(Packet *);
int undo_packet(Packet *);
void dump_packet(Packet *);
|