#include #define MYID "SSH-2.0-Plan9" #pragma varargck type "M" mpint* enum { CONNSHIFT = 7, 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 *);