1*63afb9a5SDavid du Colombier #include <u.h> 2*63afb9a5SDavid du Colombier #include <libc.h> 3*63afb9a5SDavid du Colombier #include <mp.h> 4*63afb9a5SDavid du Colombier #include <auth.h> 5*63afb9a5SDavid du Colombier #include <libsec.h> 6*63afb9a5SDavid du Colombier 7*63afb9a5SDavid du Colombier enum /* internal debugging flags */ 8*63afb9a5SDavid du Colombier { 9*63afb9a5SDavid du Colombier DBG= 1<<0, 10*63afb9a5SDavid du Colombier DBG_CRYPTO= 1<<1, 11*63afb9a5SDavid du Colombier DBG_PACKET= 1<<2, 12*63afb9a5SDavid du Colombier DBG_AUTH= 1<<3, 13*63afb9a5SDavid du Colombier DBG_PROC= 1<<4, 14*63afb9a5SDavid du Colombier DBG_PROTO= 1<<5, 15*63afb9a5SDavid du Colombier DBG_IO= 1<<6, 16*63afb9a5SDavid du Colombier DBG_SCP= 1<<7, 17*63afb9a5SDavid du Colombier }; 18*63afb9a5SDavid du Colombier 19*63afb9a5SDavid du Colombier enum /* protocol packet types */ 20*63afb9a5SDavid du Colombier { 21*63afb9a5SDavid du Colombier /* 0 */ 22*63afb9a5SDavid du Colombier SSH_MSG_NONE=0, 23*63afb9a5SDavid du Colombier SSH_MSG_DISCONNECT, 24*63afb9a5SDavid du Colombier SSH_SMSG_PUBLIC_KEY, 25*63afb9a5SDavid du Colombier SSH_CMSG_SESSION_KEY, 26*63afb9a5SDavid du Colombier SSH_CMSG_USER, 27*63afb9a5SDavid du Colombier SSH_CMSG_AUTH_RHOSTS, 28*63afb9a5SDavid du Colombier SSH_CMSG_AUTH_RSA, 29*63afb9a5SDavid du Colombier SSH_SMSG_AUTH_RSA_CHALLENGE, 30*63afb9a5SDavid du Colombier SSH_CMSG_AUTH_RSA_RESPONSE, 31*63afb9a5SDavid du Colombier SSH_CMSG_AUTH_PASSWORD, 32*63afb9a5SDavid du Colombier 33*63afb9a5SDavid du Colombier /* 10 */ 34*63afb9a5SDavid du Colombier SSH_CMSG_REQUEST_PTY, 35*63afb9a5SDavid du Colombier SSH_CMSG_WINDOW_SIZE, 36*63afb9a5SDavid du Colombier SSH_CMSG_EXEC_SHELL, 37*63afb9a5SDavid du Colombier SSH_CMSG_EXEC_CMD, 38*63afb9a5SDavid du Colombier SSH_SMSG_SUCCESS, 39*63afb9a5SDavid du Colombier SSH_SMSG_FAILURE, 40*63afb9a5SDavid du Colombier SSH_CMSG_STDIN_DATA, 41*63afb9a5SDavid du Colombier SSH_SMSG_STDOUT_DATA, 42*63afb9a5SDavid du Colombier SSH_SMSG_STDERR_DATA, 43*63afb9a5SDavid du Colombier SSH_CMSG_EOF, 44*63afb9a5SDavid du Colombier 45*63afb9a5SDavid du Colombier /* 20 */ 46*63afb9a5SDavid du Colombier SSH_SMSG_EXITSTATUS, 47*63afb9a5SDavid du Colombier SSH_MSG_CHANNEL_OPEN_CONFIRMATION, 48*63afb9a5SDavid du Colombier SSH_MSG_CHANNEL_OPEN_FAILURE, 49*63afb9a5SDavid du Colombier SSH_MSG_CHANNEL_DATA, 50*63afb9a5SDavid du Colombier SSH_MSG_CHANNEL_INPUT_EOF, 51*63afb9a5SDavid du Colombier SSH_MSG_CHANNEL_OUTPUT_CLOSED, 52*63afb9a5SDavid du Colombier SSH_MSG_UNIX_DOMAIN_X11_FORWARDING, /* obsolete */ 53*63afb9a5SDavid du Colombier SSH_SMSG_X11_OPEN, 54*63afb9a5SDavid du Colombier SSH_CMSG_PORT_FORWARD_REQUEST, 55*63afb9a5SDavid du Colombier SSH_MSG_PORT_OPEN, 56*63afb9a5SDavid du Colombier 57*63afb9a5SDavid du Colombier /* 30 */ 58*63afb9a5SDavid du Colombier SSH_CMSG_AGENT_REQUEST_FORWARDING, 59*63afb9a5SDavid du Colombier SSH_SMSG_AGENT_OPEN, 60*63afb9a5SDavid du Colombier SSH_MSG_IGNORE, 61*63afb9a5SDavid du Colombier SSH_CMSG_EXIT_CONFIRMATION, 62*63afb9a5SDavid du Colombier SSH_CMSG_X11_REQUEST_FORWARDING, 63*63afb9a5SDavid du Colombier SSH_CMSG_AUTH_RHOSTS_RSA, 64*63afb9a5SDavid du Colombier SSH_MSG_DEBUG, 65*63afb9a5SDavid du Colombier SSH_CMSG_REQUEST_COMPRESSION, 66*63afb9a5SDavid du Colombier SSH_CMSG_MAX_PACKET_SIZE, 67*63afb9a5SDavid du Colombier SSH_CMSG_AUTH_TIS, 68*63afb9a5SDavid du Colombier 69*63afb9a5SDavid du Colombier /* 40 */ 70*63afb9a5SDavid du Colombier SSH_SMSG_AUTH_TIS_CHALLENGE, 71*63afb9a5SDavid du Colombier SSH_CMSG_AUTH_TIS_RESPONSE, 72*63afb9a5SDavid du Colombier SSH_CMSG_AUTH_KERBEROS, 73*63afb9a5SDavid du Colombier SSH_SMSG_AUTH_KERBEROS_RESPONSE, 74*63afb9a5SDavid du Colombier SSH_CMSG_HAVE_KERBEROS_TGT, 75*63afb9a5SDavid du Colombier }; 76*63afb9a5SDavid du Colombier 77*63afb9a5SDavid du Colombier enum /* protocol flags */ 78*63afb9a5SDavid du Colombier { 79*63afb9a5SDavid du Colombier SSH_PROTOFLAG_SCREEN_NUMBER=1<<0, 80*63afb9a5SDavid du Colombier SSH_PROTOFLAG_HOST_IN_FWD_OPEN=1<<1, 81*63afb9a5SDavid du Colombier }; 82*63afb9a5SDavid du Colombier 83*63afb9a5SDavid du Colombier enum /* agent protocol packet types */ 84*63afb9a5SDavid du Colombier { 85*63afb9a5SDavid du Colombier SSH_AGENTC_NONE = 0, 86*63afb9a5SDavid du Colombier SSH_AGENTC_REQUEST_RSA_IDENTITIES, 87*63afb9a5SDavid du Colombier SSH_AGENT_RSA_IDENTITIES_ANSWER, 88*63afb9a5SDavid du Colombier SSH_AGENTC_RSA_CHALLENGE, 89*63afb9a5SDavid du Colombier SSH_AGENT_RSA_RESPONSE, 90*63afb9a5SDavid du Colombier SSH_AGENT_FAILURE, 91*63afb9a5SDavid du Colombier SSH_AGENT_SUCCESS, 92*63afb9a5SDavid du Colombier SSH_AGENTC_ADD_RSA_IDENTITY, 93*63afb9a5SDavid du Colombier SSH_AGENTC_REMOVE_RSA_IDENTITY, 94*63afb9a5SDavid du Colombier }; 95*63afb9a5SDavid du Colombier 96*63afb9a5SDavid du Colombier enum /* protocol constants */ 97*63afb9a5SDavid du Colombier { 98*63afb9a5SDavid du Colombier SSH_MAX_DATA = 256*1024, 99*63afb9a5SDavid du Colombier SSH_MAX_MSG = SSH_MAX_DATA+4, 100*63afb9a5SDavid du Colombier 101*63afb9a5SDavid du Colombier SESSKEYLEN = 32, 102*63afb9a5SDavid du Colombier SESSIDLEN = 16, 103*63afb9a5SDavid du Colombier 104*63afb9a5SDavid du Colombier COOKIELEN = 8, 105*63afb9a5SDavid du Colombier }; 106*63afb9a5SDavid du Colombier 107*63afb9a5SDavid du Colombier enum /* crypto ids */ 108*63afb9a5SDavid du Colombier { 109*63afb9a5SDavid du Colombier SSH_CIPHER_NONE = 0, 110*63afb9a5SDavid du Colombier SSH_CIPHER_IDEA, 111*63afb9a5SDavid du Colombier SSH_CIPHER_DES, 112*63afb9a5SDavid du Colombier SSH_CIPHER_3DES, 113*63afb9a5SDavid du Colombier SSH_CIPHER_TSS, 114*63afb9a5SDavid du Colombier SSH_CIPHER_RC4, 115*63afb9a5SDavid du Colombier SSH_CIPHER_BLOWFISH, 116*63afb9a5SDavid du Colombier SSH_CIPHER_TWIDDLE, /* for debugging */ 117*63afb9a5SDavid du Colombier }; 118*63afb9a5SDavid du Colombier 119*63afb9a5SDavid du Colombier enum /* auth method ids */ 120*63afb9a5SDavid du Colombier { 121*63afb9a5SDavid du Colombier SSH_AUTH_RHOSTS = 1, 122*63afb9a5SDavid du Colombier SSH_AUTH_RSA = 2, 123*63afb9a5SDavid du Colombier SSH_AUTH_PASSWORD = 3, 124*63afb9a5SDavid du Colombier SSH_AUTH_RHOSTS_RSA = 4, 125*63afb9a5SDavid du Colombier SSH_AUTH_TIS = 5, 126*63afb9a5SDavid du Colombier SSH_AUTH_USER_RSA = 6, 127*63afb9a5SDavid du Colombier }; 128*63afb9a5SDavid du Colombier 129*63afb9a5SDavid du Colombier typedef struct Auth Auth; 130*63afb9a5SDavid du Colombier typedef struct Authsrv Authsrv; 131*63afb9a5SDavid du Colombier typedef struct Cipher Cipher; 132*63afb9a5SDavid du Colombier typedef struct CipherState CipherState; 133*63afb9a5SDavid du Colombier typedef struct Conn Conn; 134*63afb9a5SDavid du Colombier typedef struct Msg Msg; 135*63afb9a5SDavid du Colombier 136*63afb9a5SDavid du Colombier #pragma incomplete CipherState 137*63afb9a5SDavid du Colombier 138*63afb9a5SDavid du Colombier struct Auth 139*63afb9a5SDavid du Colombier { 140*63afb9a5SDavid du Colombier int id; 141*63afb9a5SDavid du Colombier char *name; 142*63afb9a5SDavid du Colombier int (*fn)(Conn*); 143*63afb9a5SDavid du Colombier }; 144*63afb9a5SDavid du Colombier 145*63afb9a5SDavid du Colombier struct Authsrv 146*63afb9a5SDavid du Colombier { 147*63afb9a5SDavid du Colombier int id; 148*63afb9a5SDavid du Colombier char *name; 149*63afb9a5SDavid du Colombier int firstmsg; 150*63afb9a5SDavid du Colombier AuthInfo *(*fn)(Conn*, Msg*); 151*63afb9a5SDavid du Colombier }; 152*63afb9a5SDavid du Colombier 153*63afb9a5SDavid du Colombier struct Cipher 154*63afb9a5SDavid du Colombier { 155*63afb9a5SDavid du Colombier int id; 156*63afb9a5SDavid du Colombier char *name; 157*63afb9a5SDavid du Colombier CipherState *(*init)(Conn*, int isserver); 158*63afb9a5SDavid du Colombier void (*encrypt)(CipherState*, uchar*, int); 159*63afb9a5SDavid du Colombier void (*decrypt)(CipherState*, uchar*, int); 160*63afb9a5SDavid du Colombier }; 161*63afb9a5SDavid du Colombier 162*63afb9a5SDavid du Colombier struct Conn 163*63afb9a5SDavid du Colombier { 164*63afb9a5SDavid du Colombier QLock; 165*63afb9a5SDavid du Colombier int fd[2]; 166*63afb9a5SDavid du Colombier CipherState *cstate; 167*63afb9a5SDavid du Colombier uchar cookie[COOKIELEN]; 168*63afb9a5SDavid du Colombier uchar sessid[SESSIDLEN]; 169*63afb9a5SDavid du Colombier uchar sesskey[SESSKEYLEN]; 170*63afb9a5SDavid du Colombier RSApub *serverkey; 171*63afb9a5SDavid du Colombier RSApub *hostkey; 172*63afb9a5SDavid du Colombier ulong flags; 173*63afb9a5SDavid du Colombier ulong ciphermask; 174*63afb9a5SDavid du Colombier Cipher *cipher; /* chosen cipher */ 175*63afb9a5SDavid du Colombier Cipher **okcipher; /* list of acceptable ciphers */ 176*63afb9a5SDavid du Colombier int nokcipher; 177*63afb9a5SDavid du Colombier ulong authmask; 178*63afb9a5SDavid du Colombier Auth **okauth; 179*63afb9a5SDavid du Colombier int nokauth; 180*63afb9a5SDavid du Colombier char *user; 181*63afb9a5SDavid du Colombier char *host; 182*63afb9a5SDavid du Colombier char *aliases; 183*63afb9a5SDavid du Colombier int interactive; 184*63afb9a5SDavid du Colombier Msg *unget; 185*63afb9a5SDavid du Colombier 186*63afb9a5SDavid du Colombier RSApriv *serverpriv; /* server only */ 187*63afb9a5SDavid du Colombier RSApriv *hostpriv; 188*63afb9a5SDavid du Colombier Authsrv **okauthsrv; 189*63afb9a5SDavid du Colombier int nokauthsrv; 190*63afb9a5SDavid du Colombier }; 191*63afb9a5SDavid du Colombier 192*63afb9a5SDavid du Colombier struct Msg 193*63afb9a5SDavid du Colombier { 194*63afb9a5SDavid du Colombier Conn *c; 195*63afb9a5SDavid du Colombier uchar type; 196*63afb9a5SDavid du Colombier ulong len; /* output: #bytes before pos, input: #bytes after pos */ 197*63afb9a5SDavid du Colombier uchar *bp; /* beginning of allocated space */ 198*63afb9a5SDavid du Colombier uchar *rp; /* read pointer */ 199*63afb9a5SDavid du Colombier uchar *wp; /* write pointer */ 200*63afb9a5SDavid du Colombier uchar *ep; /* end of allocated space */ 201*63afb9a5SDavid du Colombier Msg *link; /* for sshnet */ 202*63afb9a5SDavid du Colombier }; 203*63afb9a5SDavid du Colombier 204*63afb9a5SDavid du Colombier #define LONG(p) (((p)[0]<<24)|((p)[1]<<16)|((p)[2]<<8)|((p)[3])) 205*63afb9a5SDavid du Colombier #define PLONG(p, l) \ 206*63afb9a5SDavid du Colombier (((p)[0]=(l)>>24),((p)[1]=(l)>>16),\ 207*63afb9a5SDavid du Colombier ((p)[2]=(l)>>8),((p)[3]=(l))) 208*63afb9a5SDavid du Colombier #define SHORT(p) (((p)[0]<<8)|(p)[1]) 209*63afb9a5SDavid du Colombier #define PSHORT(p,l) \ 210*63afb9a5SDavid du Colombier (((p)[0]=(l)>>8),((p)[1]=(l))) 211*63afb9a5SDavid du Colombier 212*63afb9a5SDavid du Colombier extern char Edecode[]; 213*63afb9a5SDavid du Colombier extern char Eencode[]; 214*63afb9a5SDavid du Colombier extern char Ememory[]; 215*63afb9a5SDavid du Colombier extern char Ehangup[]; 216*63afb9a5SDavid du Colombier extern int doabort; 217*63afb9a5SDavid du Colombier extern int debuglevel; 218*63afb9a5SDavid du Colombier 219*63afb9a5SDavid du Colombier extern Auth authpassword; 220*63afb9a5SDavid du Colombier extern Auth authrsa; 221*63afb9a5SDavid du Colombier extern Auth authtis; 222*63afb9a5SDavid du Colombier 223*63afb9a5SDavid du Colombier extern Authsrv authsrvpassword; 224*63afb9a5SDavid du Colombier extern Authsrv authsrvtis; 225*63afb9a5SDavid du Colombier 226*63afb9a5SDavid du Colombier extern Cipher cipher3des; 227*63afb9a5SDavid du Colombier extern Cipher cipherblowfish; 228*63afb9a5SDavid du Colombier extern Cipher cipherdes; 229*63afb9a5SDavid du Colombier extern Cipher cipherrc4; 230*63afb9a5SDavid du Colombier extern Cipher ciphernone; 231*63afb9a5SDavid du Colombier extern Cipher ciphertwiddle; 232*63afb9a5SDavid du Colombier 233*63afb9a5SDavid du Colombier /* msg.c */ 234*63afb9a5SDavid du Colombier Msg* allocmsg(Conn*, int, int); 235*63afb9a5SDavid du Colombier void badmsg(Msg*, int); 236*63afb9a5SDavid du Colombier Msg* recvmsg(Conn*, int); 237*63afb9a5SDavid du Colombier void unrecvmsg(Conn*, Msg*); 238*63afb9a5SDavid du Colombier int sendmsg(Msg*); 239*63afb9a5SDavid du Colombier uchar getbyte(Msg*); 240*63afb9a5SDavid du Colombier ushort getshort(Msg*); 241*63afb9a5SDavid du Colombier ulong getlong(Msg*); 242*63afb9a5SDavid du Colombier char* getstring(Msg*); 243*63afb9a5SDavid du Colombier void* getbytes(Msg*, int); 244*63afb9a5SDavid du Colombier mpint* getmpint(Msg*); 245*63afb9a5SDavid du Colombier RSApub* getRSApub(Msg*); 246*63afb9a5SDavid du Colombier void putbyte(Msg*, uchar); 247*63afb9a5SDavid du Colombier void putshort(Msg*, ushort); 248*63afb9a5SDavid du Colombier void putlong(Msg*, ulong); 249*63afb9a5SDavid du Colombier void putstring(Msg*, char*); 250*63afb9a5SDavid du Colombier void putbytes(Msg*, void*, long); 251*63afb9a5SDavid du Colombier void putmpint(Msg*, mpint*); 252*63afb9a5SDavid du Colombier void putRSApub(Msg*, RSApub*); 253*63afb9a5SDavid du Colombier mpint* rsapad(mpint*, int); 254*63afb9a5SDavid du Colombier mpint* rsaunpad(mpint*); 255*63afb9a5SDavid du Colombier void mptoberjust(mpint*, uchar*, int); 256*63afb9a5SDavid du Colombier mpint* rsaencryptbuf(RSApub*, uchar*, int); 257*63afb9a5SDavid du Colombier 258*63afb9a5SDavid du Colombier /* cmsg.c */ 259*63afb9a5SDavid du Colombier void sshclienthandshake(Conn*); 260*63afb9a5SDavid du Colombier void requestpty(Conn*); 261*63afb9a5SDavid du Colombier int readgeom(int*, int*, int*, int*); 262*63afb9a5SDavid du Colombier void sendwindowsize(Conn*, int, int, int, int); 263*63afb9a5SDavid du Colombier int rawhack; 264*63afb9a5SDavid du Colombier 265*63afb9a5SDavid du Colombier /* smsg.c */ 266*63afb9a5SDavid du Colombier void sshserverhandshake(Conn*); 267*63afb9a5SDavid du Colombier 268*63afb9a5SDavid du Colombier /* pubkey.c */ 269*63afb9a5SDavid du Colombier enum 270*63afb9a5SDavid du Colombier { 271*63afb9a5SDavid du Colombier KeyOk, 272*63afb9a5SDavid du Colombier KeyWrong, 273*63afb9a5SDavid du Colombier NoKey, 274*63afb9a5SDavid du Colombier NoKeyFile, 275*63afb9a5SDavid du Colombier }; 276*63afb9a5SDavid du Colombier int appendkey(char*, char*, RSApub*); 277*63afb9a5SDavid du Colombier int findkey(char*, char*, RSApub*); 278*63afb9a5SDavid du Colombier int replacekey(char*, char*, RSApub*); 279*63afb9a5SDavid du Colombier 280*63afb9a5SDavid du Colombier /* agent.c */ 281*63afb9a5SDavid du Colombier int startagent(Conn*); 282*63afb9a5SDavid du Colombier void handleagentmsg(Msg*); 283*63afb9a5SDavid du Colombier void handleagentopen(Msg*); 284*63afb9a5SDavid du Colombier void handleagentieof(Msg*); 285*63afb9a5SDavid du Colombier void handleagentoclose(Msg*); 286*63afb9a5SDavid du Colombier 287*63afb9a5SDavid du Colombier /* util.c */ 288*63afb9a5SDavid du Colombier void debug(int, char*, ...); 289*63afb9a5SDavid du Colombier void* emalloc(long); 290*63afb9a5SDavid du Colombier void* erealloc(void*, long); 291*63afb9a5SDavid du Colombier void error(char*, ...); 292*63afb9a5SDavid du Colombier RSApriv* readsecretkey(char*); 293*63afb9a5SDavid du Colombier int readstrnl(int, char*, int); 294*63afb9a5SDavid du Colombier void atexitkill(int); 295*63afb9a5SDavid du Colombier void atexitkiller(void); 296*63afb9a5SDavid du Colombier void calcsessid(Conn*); 297*63afb9a5SDavid du Colombier void sshlog(char*, ...); 298*63afb9a5SDavid du Colombier void setaliases(Conn*, char*); 299*63afb9a5SDavid du Colombier void privatefactotum(void); 300*63afb9a5SDavid du Colombier 301*63afb9a5SDavid du Colombier #pragma varargck argpos debug 2 302*63afb9a5SDavid du Colombier #pragma varargck argpos error 1 303*63afb9a5SDavid du Colombier #pragma varargck argpos sshlog 2 304