262 lines · 5.7 KB · C
RawDownload
#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 *);