1*63afb9a5SDavid du Colombier #include <bio.h> 2*63afb9a5SDavid du Colombier #include "ssh2.h" /* ugh */ 3*63afb9a5SDavid du Colombier 4*63afb9a5SDavid du Colombier #define MYID "SSH-2.0-Plan9" 5*63afb9a5SDavid du Colombier 6*63afb9a5SDavid du Colombier #pragma varargck type "M" mpint* 7*63afb9a5SDavid du Colombier 8*63afb9a5SDavid du Colombier enum { 9*63afb9a5SDavid du Colombier Server = 0, 10*63afb9a5SDavid du Colombier Client, 11*63afb9a5SDavid du Colombier 12*63afb9a5SDavid du Colombier Maxpktpay = 35000, 13*63afb9a5SDavid du Colombier 14*63afb9a5SDavid du Colombier /* qid.path components: level (2), type (4), conn (7), chan (7) */ 15*63afb9a5SDavid du Colombier Connshift = 7, 16*63afb9a5SDavid du Colombier MAXCONN = 1 << Connshift, /* also Maxchan */ 17*63afb9a5SDavid du Colombier Chanmask = MAXCONN - 1, 18*63afb9a5SDavid du Colombier Connmask = Chanmask, 19*63afb9a5SDavid du Colombier 20*63afb9a5SDavid du Colombier Qtypeshift = 2 * Connshift, /* conn + chan */ 21*63afb9a5SDavid du Colombier 22*63afb9a5SDavid du Colombier Qroot = 0, 23*63afb9a5SDavid du Colombier Qclone = 1 << Qtypeshift, 24*63afb9a5SDavid du Colombier Qctl = 2 << Qtypeshift, 25*63afb9a5SDavid du Colombier Qdata = 3 << Qtypeshift, 26*63afb9a5SDavid du Colombier Qlisten = 4 << Qtypeshift, 27*63afb9a5SDavid du Colombier Qlocal = 5 << Qtypeshift, 28*63afb9a5SDavid du Colombier Qreqrem = 6 << Qtypeshift, /* request or remote */ 29*63afb9a5SDavid du Colombier Qstatus = 7 << Qtypeshift, 30*63afb9a5SDavid du Colombier Qtcp = 8 << Qtypeshift, 31*63afb9a5SDavid du Colombier Qtypemask = 017 << Qtypeshift, 32*63afb9a5SDavid du Colombier 33*63afb9a5SDavid du Colombier Levshift = Qtypeshift + 4, 34*63afb9a5SDavid du Colombier 35*63afb9a5SDavid du Colombier /* levels of /net/ssh hierarchy */ 36*63afb9a5SDavid du Colombier Top = 0, 37*63afb9a5SDavid du Colombier Connection, 38*63afb9a5SDavid du Colombier Subchannel, 39*63afb9a5SDavid du Colombier }; 40*63afb9a5SDavid du Colombier 41*63afb9a5SDavid du Colombier /* 42*63afb9a5SDavid du Colombier * The stylistic anomaly with these names of unbounded length 43*63afb9a5SDavid du Colombier * is a result of following the RFCs in using the same names for 44*63afb9a5SDavid du Colombier * these constants. I did that to make it easier to search and 45*63afb9a5SDavid du Colombier * cross-reference between the code and the RFCs. 46*63afb9a5SDavid du Colombier */ 47*63afb9a5SDavid du Colombier enum { /* SSH2 Protocol Packet Types */ 48*63afb9a5SDavid du Colombier SSH_MSG_DISCONNECT = 1, 49*63afb9a5SDavid du Colombier SSH_MSG_IGNORE = 2, 50*63afb9a5SDavid du Colombier SSH_MSG_UNIMPLEMENTED, 51*63afb9a5SDavid du Colombier SSH_MSG_DEBUG, 52*63afb9a5SDavid du Colombier SSH_MSG_SERVICE_REQUEST, 53*63afb9a5SDavid du Colombier SSH_MSG_SERVICE_ACCEPT, 54*63afb9a5SDavid du Colombier 55*63afb9a5SDavid du Colombier SSH_MSG_KEXINIT = 20, 56*63afb9a5SDavid du Colombier SSH_MSG_NEWKEYS, 57*63afb9a5SDavid du Colombier 58*63afb9a5SDavid du Colombier SSH_MSG_KEXDH_INIT = 30, 59*63afb9a5SDavid du Colombier SSH_MSG_KEXDH_REPLY, 60*63afb9a5SDavid du Colombier 61*63afb9a5SDavid du Colombier SSH_MSG_USERAUTH_REQUEST = 50, 62*63afb9a5SDavid du Colombier SSH_MSG_USERAUTH_FAILURE, 63*63afb9a5SDavid du Colombier SSH_MSG_USERAUTH_SUCCESS, 64*63afb9a5SDavid du Colombier SSH_MSG_USERAUTH_BANNER, 65*63afb9a5SDavid du Colombier 66*63afb9a5SDavid du Colombier SSH_MSG_USERAUTH_PK_OK = 60, 67*63afb9a5SDavid du Colombier SSH_MSG_USERAUTH_PASSWD_CHANGEREQ = 60, 68*63afb9a5SDavid du Colombier 69*63afb9a5SDavid du Colombier SSH_MSG_GLOBAL_REQUEST = 80, 70*63afb9a5SDavid du Colombier SSH_MSG_REQUEST_SUCCESS, 71*63afb9a5SDavid du Colombier SSH_MSG_REQUEST_FAILURE, 72*63afb9a5SDavid du Colombier 73*63afb9a5SDavid du Colombier SSH_MSG_CHANNEL_OPEN = 90, 74*63afb9a5SDavid du Colombier SSH_MSG_CHANNEL_OPEN_CONFIRMATION, 75*63afb9a5SDavid du Colombier SSH_MSG_CHANNEL_OPEN_FAILURE, 76*63afb9a5SDavid du Colombier SSH_MSG_CHANNEL_WINDOW_ADJUST, 77*63afb9a5SDavid du Colombier SSH_MSG_CHANNEL_DATA, 78*63afb9a5SDavid du Colombier SSH_MSG_CHANNEL_EXTENDED_DATA, 79*63afb9a5SDavid du Colombier SSH_MSG_CHANNEL_EOF, 80*63afb9a5SDavid du Colombier SSH_MSG_CHANNEL_CLOSE, 81*63afb9a5SDavid du Colombier SSH_MSG_CHANNEL_REQUEST, 82*63afb9a5SDavid du Colombier SSH_MSG_CHANNEL_SUCCESS, 83*63afb9a5SDavid du Colombier SSH_MSG_CHANNEL_FAILURE, 84*63afb9a5SDavid du Colombier }; 85*63afb9a5SDavid du Colombier 86*63afb9a5SDavid du Colombier enum { /* SSH2 reason codes */ 87*63afb9a5SDavid du Colombier SSH_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT = 1, 88*63afb9a5SDavid du Colombier SSH_DISCONNECT_PROTOCOL_ERROR, 89*63afb9a5SDavid du Colombier SSH_DISCONNECT_KEY_EXCHANGE_FAILED, 90*63afb9a5SDavid du Colombier SSH_DISCONNECT_RESERVED, 91*63afb9a5SDavid du Colombier SSH_DISCONNECT_MAC_ERROR, 92*63afb9a5SDavid du Colombier SSH_DISCONNECT_COMPRESSION_ERROR, 93*63afb9a5SDavid du Colombier SSH_DISCONNECT_SERVICE_NOT_AVAILABLE, 94*63afb9a5SDavid du Colombier SSH_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED, 95*63afb9a5SDavid du Colombier SSH_DISCONNECT_HOST_KEY_NOT_VERIFIABLE, 96*63afb9a5SDavid du Colombier SSH_DISCONNECT_CONNECTION_LOST, 97*63afb9a5SDavid du Colombier SSH_DISCONNECT_BY_APPLICATION, 98*63afb9a5SDavid du Colombier SSH_DISCONNECT_TOO_MANY_CONNECTIONS, 99*63afb9a5SDavid du Colombier SSH_DISCONNECT_AUTH_CANCELLED_BY_USER, 100*63afb9a5SDavid du Colombier SSH_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE, 101*63afb9a5SDavid du Colombier SSH_DISCONNECT_ILLEGAL_USR_NAME, 102*63afb9a5SDavid du Colombier 103*63afb9a5SDavid du Colombier SSH_OPEN_ADMINISTRATIVELY_PROHIBITED = 1, 104*63afb9a5SDavid du Colombier SSH_OPEN_CONNECT_FAILED, 105*63afb9a5SDavid du Colombier SSH_OPEN_UNKNOWN_CHANNEL_TYPE, 106*63afb9a5SDavid du Colombier SSH_OPEN_RESOURCE_SHORTAGE, 107*63afb9a5SDavid du Colombier }; 108*63afb9a5SDavid du Colombier 109*63afb9a5SDavid du Colombier enum { /* SSH2 type code */ 110*63afb9a5SDavid du Colombier SSH_EXTENDED_DATA_STDERR = 1, 111*63afb9a5SDavid du Colombier }; 112*63afb9a5SDavid du Colombier 113*63afb9a5SDavid du Colombier enum { /* connection and channel states */ 114*63afb9a5SDavid du Colombier Empty = 0, 115*63afb9a5SDavid du Colombier Allocated, 116*63afb9a5SDavid du Colombier Initting, 117*63afb9a5SDavid du Colombier Listening, 118*63afb9a5SDavid du Colombier Opening, 119*63afb9a5SDavid du Colombier Negotiating, 120*63afb9a5SDavid du Colombier Authing, 121*63afb9a5SDavid du Colombier Established, 122*63afb9a5SDavid du Colombier Eof, 123*63afb9a5SDavid du Colombier Closing, 124*63afb9a5SDavid du Colombier Closed, 125*63afb9a5SDavid du Colombier }; 126*63afb9a5SDavid du Colombier 127*63afb9a5SDavid du Colombier enum { 128*63afb9a5SDavid du Colombier NoKeyFile, 129*63afb9a5SDavid du Colombier NoKey, 130*63afb9a5SDavid du Colombier KeyWrong, 131*63afb9a5SDavid du Colombier KeyOk, 132*63afb9a5SDavid du Colombier }; 133*63afb9a5SDavid du Colombier 134*63afb9a5SDavid du Colombier typedef struct Cipher Cipher; 135*63afb9a5SDavid du Colombier typedef struct CipherState CipherState; 136*63afb9a5SDavid du Colombier typedef struct Conn Conn; 137*63afb9a5SDavid du Colombier typedef struct Kex Kex; 138*63afb9a5SDavid du Colombier typedef struct MBox MBox; 139*63afb9a5SDavid du Colombier typedef struct PKA PKA; 140*63afb9a5SDavid du Colombier typedef struct Packet Packet; 141*63afb9a5SDavid du Colombier typedef struct Plist Plist; 142*63afb9a5SDavid du Colombier typedef struct SSHChan SSHChan; 143*63afb9a5SDavid du Colombier 144*63afb9a5SDavid du Colombier #pragma incomplete CipherState 145*63afb9a5SDavid du Colombier 146*63afb9a5SDavid du Colombier struct Plist { 147*63afb9a5SDavid du Colombier Packet *pack; 148*63afb9a5SDavid du Colombier uchar *st; 149*63afb9a5SDavid du Colombier int rem; 150*63afb9a5SDavid du Colombier Plist *next; 151*63afb9a5SDavid du Colombier }; 152*63afb9a5SDavid du Colombier 153*63afb9a5SDavid du Colombier struct SSHChan { 154*63afb9a5SDavid du Colombier Rendez r; /* awaiting input? */ 155*63afb9a5SDavid du Colombier int id; 156*63afb9a5SDavid du Colombier int otherid; 157*63afb9a5SDavid du Colombier int state; 158*63afb9a5SDavid du Colombier int waker; 159*63afb9a5SDavid du Colombier int conn; 160*63afb9a5SDavid du Colombier ulong rwindow; 161*63afb9a5SDavid du Colombier ulong twindow; 162*63afb9a5SDavid du Colombier ulong sent; 163*63afb9a5SDavid du Colombier ulong inrqueue; 164*63afb9a5SDavid du Colombier char *ann; 165*63afb9a5SDavid du Colombier Req *lreq; 166*63afb9a5SDavid du Colombier 167*63afb9a5SDavid du Colombier /* File* for each Qid type */ 168*63afb9a5SDavid du Colombier File *dir; 169*63afb9a5SDavid du Colombier File *ctl; 170*63afb9a5SDavid du Colombier File *data; 171*63afb9a5SDavid du Colombier File *listen; 172*63afb9a5SDavid du Colombier File *request; 173*63afb9a5SDavid du Colombier File *status; 174*63afb9a5SDavid du Colombier File *tcp; 175*63afb9a5SDavid du Colombier 176*63afb9a5SDavid du Colombier Plist *dataq; 177*63afb9a5SDavid du Colombier Plist *datatl; 178*63afb9a5SDavid du Colombier Plist *reqq; 179*63afb9a5SDavid du Colombier Plist *reqtl; 180*63afb9a5SDavid du Colombier 181*63afb9a5SDavid du Colombier Channel *inchan; 182*63afb9a5SDavid du Colombier Channel *reqchan; 183*63afb9a5SDavid du Colombier QLock xmtlock; 184*63afb9a5SDavid du Colombier Rendez xmtrendez; 185*63afb9a5SDavid du Colombier }; 186*63afb9a5SDavid du Colombier 187*63afb9a5SDavid du Colombier struct Conn { 188*63afb9a5SDavid du Colombier QLock l; 189*63afb9a5SDavid du Colombier Rendez r; /* awaiting input? */ 190*63afb9a5SDavid du Colombier 191*63afb9a5SDavid du Colombier Ioproc *dio; 192*63afb9a5SDavid du Colombier Ioproc *cio; 193*63afb9a5SDavid du Colombier Ioproc *rio; 194*63afb9a5SDavid du Colombier 195*63afb9a5SDavid du Colombier int state; 196*63afb9a5SDavid du Colombier int role; 197*63afb9a5SDavid du Colombier int id; 198*63afb9a5SDavid du Colombier 199*63afb9a5SDavid du Colombier char *remote; 200*63afb9a5SDavid du Colombier char *user; 201*63afb9a5SDavid du Colombier char *password; 202*63afb9a5SDavid du Colombier 203*63afb9a5SDavid du Colombier char *service; 204*63afb9a5SDavid du Colombier char *cap; 205*63afb9a5SDavid du Colombier char *authkey; 206*63afb9a5SDavid du Colombier int nchan; 207*63afb9a5SDavid du Colombier 208*63afb9a5SDavid du Colombier /* underlying tcp connection */ 209*63afb9a5SDavid du Colombier int datafd; 210*63afb9a5SDavid du Colombier int ctlfd; 211*63afb9a5SDavid du Colombier int stifle; /* flag: no i/o between listen and sshsession */ 212*63afb9a5SDavid du Colombier int poisoned; 213*63afb9a5SDavid du Colombier int tcpconn; 214*63afb9a5SDavid du Colombier 215*63afb9a5SDavid du Colombier int rpid; 216*63afb9a5SDavid du Colombier 217*63afb9a5SDavid du Colombier int inseq; 218*63afb9a5SDavid du Colombier int outseq; 219*63afb9a5SDavid du Colombier int kexalg; 220*63afb9a5SDavid du Colombier int pkalg; 221*63afb9a5SDavid du Colombier 222*63afb9a5SDavid du Colombier int cscrypt; 223*63afb9a5SDavid du Colombier int ncscrypt; 224*63afb9a5SDavid du Colombier int sccrypt; 225*63afb9a5SDavid du Colombier int nsccrypt; 226*63afb9a5SDavid du Colombier 227*63afb9a5SDavid du Colombier int csmac; 228*63afb9a5SDavid du Colombier int ncsmac; 229*63afb9a5SDavid du Colombier int scmac; 230*63afb9a5SDavid du Colombier int nscmac; 231*63afb9a5SDavid du Colombier 232*63afb9a5SDavid du Colombier int encrypt; 233*63afb9a5SDavid du Colombier int decrypt; 234*63afb9a5SDavid du Colombier 235*63afb9a5SDavid du Colombier int outmac; 236*63afb9a5SDavid du Colombier int inmac; 237*63afb9a5SDavid du Colombier 238*63afb9a5SDavid du Colombier /* File* for each Qid type */ 239*63afb9a5SDavid du Colombier File *dir; 240*63afb9a5SDavid du Colombier File *clonefile; 241*63afb9a5SDavid du Colombier File *ctlfile; 242*63afb9a5SDavid du Colombier File *datafile; 243*63afb9a5SDavid du Colombier File *listenfile; 244*63afb9a5SDavid du Colombier File *localfile; 245*63afb9a5SDavid du Colombier File *remotefile; 246*63afb9a5SDavid du Colombier File *statusfile; 247*63afb9a5SDavid du Colombier File *tcpfile; 248*63afb9a5SDavid du Colombier 249*63afb9a5SDavid du Colombier Packet *skexinit; 250*63afb9a5SDavid du Colombier Packet *rkexinit; 251*63afb9a5SDavid du Colombier mpint *x; 252*63afb9a5SDavid du Colombier mpint *e; 253*63afb9a5SDavid du Colombier int got_sessid; 254*63afb9a5SDavid du Colombier uchar sessid[SHA1dlen]; 255*63afb9a5SDavid du Colombier 256*63afb9a5SDavid du Colombier uchar c2siv[SHA1dlen*2]; 257*63afb9a5SDavid du Colombier uchar nc2siv[SHA1dlen*2]; 258*63afb9a5SDavid du Colombier uchar s2civ[SHA1dlen*2]; 259*63afb9a5SDavid du Colombier uchar ns2civ[SHA1dlen*2]; 260*63afb9a5SDavid du Colombier 261*63afb9a5SDavid du Colombier uchar c2sek[SHA1dlen*2]; 262*63afb9a5SDavid du Colombier uchar nc2sek[SHA1dlen*2]; 263*63afb9a5SDavid du Colombier uchar s2cek[SHA1dlen*2]; 264*63afb9a5SDavid du Colombier uchar ns2cek[SHA1dlen*2]; 265*63afb9a5SDavid du Colombier 266*63afb9a5SDavid du Colombier uchar c2sik[SHA1dlen*2]; 267*63afb9a5SDavid du Colombier uchar nc2sik[SHA1dlen*2]; 268*63afb9a5SDavid du Colombier uchar s2cik[SHA1dlen*2]; 269*63afb9a5SDavid du Colombier uchar ns2cik[SHA1dlen*2]; 270*63afb9a5SDavid du Colombier 271*63afb9a5SDavid du Colombier char *otherid; 272*63afb9a5SDavid du Colombier uchar *inik; 273*63afb9a5SDavid du Colombier uchar *outik; 274*63afb9a5SDavid du Colombier CipherState *s2ccs; 275*63afb9a5SDavid du Colombier CipherState *c2scs; 276*63afb9a5SDavid du Colombier CipherState *enccs; 277*63afb9a5SDavid du Colombier CipherState *deccs; 278*63afb9a5SDavid du Colombier SSHChan *chans[MAXCONN]; 279*63afb9a5SDavid du Colombier 280*63afb9a5SDavid du Colombier char idstring[256]; /* max allowed by SSH spec */ 281*63afb9a5SDavid du Colombier }; 282*63afb9a5SDavid du Colombier 283*63afb9a5SDavid du Colombier struct Packet { 284*63afb9a5SDavid du Colombier Conn *c; 285*63afb9a5SDavid du Colombier ulong rlength; 286*63afb9a5SDavid du Colombier ulong tlength; 287*63afb9a5SDavid du Colombier uchar nlength[4]; 288*63afb9a5SDavid du Colombier uchar pad_len; 289*63afb9a5SDavid du Colombier uchar payload[Maxpktpay]; 290*63afb9a5SDavid du Colombier }; 291*63afb9a5SDavid du Colombier 292*63afb9a5SDavid du Colombier struct Cipher { 293*63afb9a5SDavid du Colombier char *name; 294*63afb9a5SDavid du Colombier int blklen; 295*63afb9a5SDavid du Colombier CipherState *(*init)(Conn*, int); 296*63afb9a5SDavid du Colombier void (*encrypt)(CipherState*, uchar*, int); 297*63afb9a5SDavid du Colombier void (*decrypt)(CipherState*, uchar*, int); 298*63afb9a5SDavid du Colombier }; 299*63afb9a5SDavid du Colombier 300*63afb9a5SDavid du Colombier struct Kex { 301*63afb9a5SDavid du Colombier char *name; 302*63afb9a5SDavid du Colombier int (*serverkex)(Conn *, Packet *); 303*63afb9a5SDavid du Colombier int (*clientkex1)(Conn *, Packet *); 304*63afb9a5SDavid du Colombier int (*clientkex2)(Conn *, Packet *); 305*63afb9a5SDavid du Colombier }; 306*63afb9a5SDavid du Colombier 307*63afb9a5SDavid du Colombier struct PKA { 308*63afb9a5SDavid du Colombier char *name; 309*63afb9a5SDavid du Colombier Packet *(*ks)(Conn *); 310*63afb9a5SDavid du Colombier Packet *(*sign)(Conn *, uchar *, int); 311*63afb9a5SDavid du Colombier int (*verify)(Conn *, uchar *, int, char *, char *, int); 312*63afb9a5SDavid du Colombier }; 313*63afb9a5SDavid du Colombier 314*63afb9a5SDavid du Colombier struct MBox { 315*63afb9a5SDavid du Colombier Channel *mchan; 316*63afb9a5SDavid du Colombier char *msg; 317*63afb9a5SDavid du Colombier int state; 318*63afb9a5SDavid du Colombier }; 319*63afb9a5SDavid du Colombier 320*63afb9a5SDavid du Colombier extern Cipher cipheraes128, cipheraes192, cipheraes256; 321*63afb9a5SDavid du Colombier extern Cipher cipherblowfish, cipher3des, cipherrc4; 322*63afb9a5SDavid du Colombier extern int debug; 323*63afb9a5SDavid du Colombier extern int sshkeychan[]; 324*63afb9a5SDavid du Colombier extern Kex dh1sha1, dh14sha1; 325*63afb9a5SDavid du Colombier extern MBox keymbox; 326*63afb9a5SDavid du Colombier extern PKA rsa_pka, dss_pka, *pkas[]; 327*63afb9a5SDavid du Colombier 328*63afb9a5SDavid du Colombier /* pubkey.c */ 329*63afb9a5SDavid du Colombier int appendkey(char *, char *, RSApub *); 330*63afb9a5SDavid du Colombier int findkey(char *, char *, RSApub *); 331*63afb9a5SDavid du Colombier RSApub *readpublickey(Biobuf *, char **); 332*63afb9a5SDavid du Colombier int replacekey(char *, char *, RSApub *); 333*63afb9a5SDavid du Colombier 334*63afb9a5SDavid du Colombier /* dh.c */ 335*63afb9a5SDavid du Colombier void dh_init(PKA *[]); 336*63afb9a5SDavid du Colombier 337*63afb9a5SDavid du Colombier /* transport.c */ 338*63afb9a5SDavid du Colombier void add_block(Packet *, void *, int); 339*63afb9a5SDavid du Colombier void add_byte(Packet *, char); 340*63afb9a5SDavid du Colombier void add_mp(Packet *, mpint *); 341*63afb9a5SDavid du Colombier int add_packet(Packet *, void *, int); 342*63afb9a5SDavid du Colombier void add_string(Packet *, char *); 343*63afb9a5SDavid du Colombier void add_uint32(Packet *, ulong); 344*63afb9a5SDavid du Colombier void dump_packet(Packet *); 345*63afb9a5SDavid du Colombier int finish_packet(Packet *); 346*63afb9a5SDavid du Colombier mpint *get_mp(uchar *q); 347*63afb9a5SDavid du Colombier uchar *get_string(Packet *, uchar *, char *, int, int *); 348*63afb9a5SDavid du Colombier ulong get_uint32(Packet *, uchar **); 349*63afb9a5SDavid du Colombier void init_packet(Packet *); 350*63afb9a5SDavid du Colombier Packet *new_packet(Conn *); 351*63afb9a5SDavid du Colombier int undo_packet(Packet *); 352