#include <bio.h>
#include "ssh2.h" /* ugh */
#define MYID "SSH-2.0-Plan9"
#pragma varargck type "M" mpint*
enum {
Server = 0,
Client,
Maxpktpay = 35000,
/* qid.path components: level (2), type (4), conn (7), chan (7) */
Connshift = 7,
MAXCONN = 1 << Connshift, /* also Maxchan */
Chanmask = MAXCONN - 1,
Connmask = Chanmask,
Qtypeshift = 2 * Connshift, /* conn + chan */
Qroot = 0,
Qclone = 1 << Qtypeshift,
Qctl = 2 << Qtypeshift,
Qdata = 3 << Qtypeshift,
Qlisten = 4 << Qtypeshift,
Qlocal = 5 << Qtypeshift,
Qreqrem = 6 << Qtypeshift, /* request or remote */
Qstatus = 7 << Qtypeshift,
Qtcp = 8 << Qtypeshift,
Qtypemask = 017 << Qtypeshift,
Levshift = Qtypeshift + 4,
/* levels of /net/ssh hierarchy */
Top = 0,
Connection,
Subchannel,
};
/*
* 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 Cipher Cipher;
typedef struct CipherState CipherState;
typedef struct Conn Conn;
typedef struct Kex Kex;
typedef struct MBox MBox;
typedef struct PKA PKA;
typedef struct Packet Packet;
typedef struct Plist Plist;
typedef struct SSHChan SSHChan;
#pragma incomplete CipherState
struct Plist {
Packet *pack;
uchar *st;
int rem;
Plist *next;
};
struct SSHChan {
Rendez r; /* awaiting input? */
int id;
int otherid;
int state;
int waker;
int conn;
ulong rwindow;
ulong twindow;
ulong sent;
ulong inrqueue;
char *ann;
Req *lreq;
/* File* for each Qid type */
File *dir;
File *ctl;
File *data;
File *listen;
File *request;
File *status;
File *tcp;
Plist *dataq;
Plist *datatl;
Plist *reqq;
Plist *reqtl;
Channel *inchan;
Channel *reqchan;
QLock xmtlock;
Rendez xmtrendez;
};
struct Conn {
QLock l;
Rendez r; /* awaiting input? */
Ioproc *dio;
Ioproc *cio;
Ioproc *rio;
int state;
int role;
int id;
char *remote;
char *user;
char *password;
char *service;
char *cap;
char *authkey;
int nchan;
/* underlying tcp connection */
int datafd;
int ctlfd;
int stifle; /* flag: no i/o between listen and sshsession */
int poisoned;
int tcpconn;
int rpid;
int inseq;
int outseq;
int kexalg;
int pkalg;
int cscrypt;
int ncscrypt;
int sccrypt;
int nsccrypt;
int csmac;
int ncsmac;
int scmac;
int nscmac;
int encrypt;
int decrypt;
int outmac;
int inmac;
/* File* for each Qid type */
File *dir;
File *clonefile;
File *ctlfile;
File *datafile;
File *listenfile;
File *localfile;
File *remotefile;
File *statusfile;
File *tcpfile;
Packet *skexinit;
Packet *rkexinit;
mpint *x;
mpint *e;
int got_sessid;
uchar sessid[SHA1dlen];
uchar c2siv[SHA1dlen*2];
uchar nc2siv[SHA1dlen*2];
uchar s2civ[SHA1dlen*2];
uchar ns2civ[SHA1dlen*2];
uchar c2sek[SHA1dlen*2];
uchar nc2sek[SHA1dlen*2];
uchar s2cek[SHA1dlen*2];
uchar ns2cek[SHA1dlen*2];
uchar c2sik[SHA1dlen*2];
uchar nc2sik[SHA1dlen*2];
uchar s2cik[SHA1dlen*2];
uchar ns2cik[SHA1dlen*2];
char *otherid;
uchar *inik;
uchar *outik;
CipherState *s2ccs;
CipherState *c2scs;
CipherState *enccs;
CipherState *deccs;
SSHChan *chans[MAXCONN];
char idstring[256]; /* max allowed by SSH spec */
};
struct Packet {
Conn *c;
ulong rlength;
ulong tlength;
uchar nlength[4];
uchar pad_len;
uchar payload[Maxpktpay];
};
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 Cipher cipheraes128, cipheraes192, cipheraes256;
extern Cipher cipherblowfish, cipher3des, cipherrc4;
extern int debug;
extern int sshkeychan[];
extern Kex dh1sha1, dh14sha1;
extern MBox keymbox;
extern PKA rsa_pka, dss_pka, *pkas[];
/* pubkey.c */
int appendkey(char *, char *, RSApub *);
int findkey(char *, char *, RSApub *);
RSApub *readpublickey(Biobuf *, char **);
int replacekey(char *, char *, RSApub *);
/* dh.c */
void dh_init(PKA *[]);
/* transport.c */
void add_block(Packet *, void *, int);
void add_byte(Packet *, char);
void add_mp(Packet *, mpint *);
int add_packet(Packet *, void *, int);
void add_string(Packet *, char *);
void add_uint32(Packet *, ulong);
void dump_packet(Packet *);
int finish_packet(Packet *);
mpint *get_mp(uchar *q);
uchar *get_string(Packet *, uchar *, char *, int, int *);
ulong get_uint32(Packet *, uchar **);
void init_packet(Packet *);
Packet *new_packet(Conn *);
int undo_packet(Packet *);
|