Subversion Repositories planix.SVN

Rev

Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

#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 *);