ref: df634b2ca4bd940a61946a3bbda3881bed1a09d6
parent: baf602582a840a0253900d41a2f1cce7156dd770
author: Yaroslav Kolomiiets <[email protected]>
date: Mon Mar 21 16:08:44 EDT 2016
* parsing and processing is largely separate * most globals went into Rdp* context * some functions merged * some put/gets lined up to an extent to feel symmerical * some cosmetic renames * other minor tweaks
--- /dev/null
+++ b/README.md
@@ -1,0 +1,3 @@
+# README #
+
+*Rd* is a remote desktop client for Plan 9 operating system implementing RDP, the Microsoft's Remote Desktop Protocol. Initially started as a feature-cut fork of the X11 *rdesktop* client, it eventually grew into something different. It does not support pre-RDP5 protocol versions and requires the server to support an equivalent of *STARTTLS* (Windows XP SP2/2003 and up). The X.509 certs presented by servers are checked with `okThumbprint` against the list kept in `/sys/lib/tls/rdp` file.
\ No newline at end of file
--- a/cap.c
+++ b/cap.c
@@ -4,81 +4,162 @@
#include "dat.h"
#include "fns.h"
-/* 2.2.7.1.1 General Capability Set (TS_GENERAL_CAPABILITYSET) */
-void
-scangencaps(uchar* p, uchar* ep)
+enum /* 2.2.7 Capability Sets; T.128 */
{
- int extraFlags, canrefresh, cansupress;
+ CapGeneral= 1,
+ CapBitmap= 2,
+ CapOrder= 3,
+ CapPointer= 8,
+ CapBitcache2= 19,
+ CapInput= 13,
+ CapSound= 12,
+ CapGlyph= 16,
- if(p+22>ep)
- sysfatal(Eshort);
- extraFlags = GSHORT(p+14);
- USED(extraFlags);
- canrefresh = p[22];
- cansupress = p[23];
- if(!canrefresh)
- sysfatal("server lacks support for Refresh Rect PDU");
- if(!cansupress)
- sysfatal("server lacks support for Suppress Output PDU");
-}
+ /* 2.2.7.1.1 General Capability Set (TS_GENERAL_CAPABILITYSET) */
+ CanFastpath= 0x0001,
+ NoBitcomphdr= 0x0400,
+ CanLongcred= 0x0004,
+};
-/* 2.2.7.1.2 Bitmap Capability Set (TS_BITMAP_CAPABILITYSET) */
-void
-scanbitcaps(uchar* p, uchar* ep)
+static int putncap(uchar*,uint,Caps*);
+static int putbitcaps(uchar*,uint,Caps*);
+static int putgencaps(uchar*,uint,Caps*);
+static int putordcaps(uchar*,uint,Caps*);
+static int putbc2caps(uchar*,uint,Caps*);
+static int putptrcaps(uchar*,uint,Caps*);
+static int putinpcaps(uchar*,uint,Caps*);
+static int putsndcaps(uchar*,uint,Caps*);
+static int putglycaps(uchar*,uint,Caps*);
+
+static
+struct {
+ int size;
+ int (*putcap)(uchar*,uint,Caps*);
+} ctab[]=
{
- int w, h, depth;
+ { 4, putncap },
+ { 24, putgencaps },
+ { 30, putbitcaps },
+ { 88, putordcaps },
+ { 40, putbc2caps },
+ { 8, putptrcaps },
+ { 88, putinpcaps },
+ { 8, putsndcaps },
+ { 52, putglycaps },
+};
- if(p+16> ep)
- sysfatal(Eshort);
- depth = GSHORT(p+4);
- w = GSHORT(p+12);
- h = GSHORT(p+14);
+int
+getcaps(Caps* caps, uchar* a, uint nb)
+{
+ int ncap, type, len;
+ uchar *p, *ep;
+ int extraFlags;
- if(depth != rd.depth){
- rd.depth = depth;
- switch(depth){
- case 8:
- rd.chan = CMAP8;
+ p = a;
+ ep = p+nb;
+ memset(caps, sizeof(*caps), 0);
+
+ ncap = GSHORT(p);
+ p += 4;
+ for(; ncap>0 && p+4<ep; ncap--){
+ type = GSHORT(p+0);
+ len = GSHORT(p+2);
+ if(p+len > ep){
+ werrstr("bad length in server's capability set");
+ return -1;
+ }
+ switch(type){
+ case CapGeneral:
+ /* 2.2.7.1.1 General Capability Set (TS_GENERAL_CAPABILITYSET) */
+ if(len < 24){
+ werrstr(Eshort);
+ return -1;
+ }
+ caps->general = 1;
+ extraFlags = GSHORT(p+14);
+ caps->canrefresh = p[22];
+ caps->cansupress = p[23];
+ USED(extraFlags);
break;
- case 15:
- rd.chan = RGB15;
+ case CapBitmap:
+ /* 2.2.7.1.2 Bitmap Capability Set (TS_BITMAP_CAPABILITYSET) */
+ if(len < 16){
+ werrstr(Eshort);
+ return -1;
+ }
+ caps->bitmap = 1;
+ caps->depth = GSHORT(p+4);
+ caps->width = GSHORT(p+12);
+ caps->height = GSHORT(p+14);
break;
- case 16:
- rd.chan = RGB16;
- break;
- case 24:
- rd.chan = RGB24;
- break;
- case 32:
- rd.chan = XRGB32;
- break;
- default:
- sysfatal("Unsupported server color depth: %uhd\n", depth);
}
+ p += len;
}
- if(w != rd.dim.x || h != rd.dim.y){
- rd.dim.x = w;
- rd.dim.y = h;
- rd.dim.x = (rd.dim.x + 3) & ~3; /* ensure width divides by 4 */
+ return p-a;
+}
+
+int
+sizecaps(Caps*)
+{
+ int i, n;
+
+ n = 0;
+ for(i = 0; i < nelem(ctab); i++)
+ n += ctab[i].size;
+ return n;
+}
+
+int
+putcaps(uchar* a, uint nb, Caps* caps)
+{
+ uchar *p, *ep;
+ int i, n;
+
+ p = a;
+ ep = a+nb;
+
+ for(i = 0; i < nelem(ctab); i++){
+ n = ctab[i].putcap(p, ep-p, caps);
+ if(n < 0)
+ return -1;
+ p += n;
}
+ return p-a;
}
+static int
+putncap(uchar *p, uint nb, Caps*)
+{
+ int ncap;
+
+ ncap = 8;
+
+ if(nb<4){
+ werrstr(Eshort);
+ return -1;
+ }
+ PSHORT(p, ncap);
+ PSHORT(p+2, 0);
+ return 4;
+}
+
/* 2.2.7.1.1 General Capability Set (TS_GENERAL_CAPABILITYSET) */
-uchar*
-putgencaps(uchar *p, uchar *ep)
+static int
+putgencaps(uchar *p, uint nb, Caps*)
{
int extraFlags;
-
+
extraFlags = 0
| CanFastpath
| NoBitcomphdr
| CanLongcred
- ;
-
- if(p+24>ep)
- sysfatal(Eshort);
+ ;
+ if(nb<24){
+ werrstr(Eshort);
+ return -1;
+ }
PSHORT(p+0, CapGeneral);
- PSHORT(p+2, GENCAPSIZE);
+ PSHORT(p+2, 24); // size
PSHORT(p+4, 0); // OSMAJORTYPE_UNSPECIFIED
PSHORT(p+6, 0); // OSMINORTYPE_UNSPECIFIED
PSHORT(p+8, 0x200); // TS_CAPS_PROTOCOLVERSION
@@ -89,24 +170,26 @@
PSHORT(p+20, 0); // generalCompressionLevel
p[22] = 0; // refreshRectSupport - server only
p[23] = 0; // suppressOutputSupport - server only
- return p+24;
+ return 24;
}
/* 2.2.7.1.2 Bitmap Capability Set (TS_BITMAP_CAPABILITYSET) */
-uchar*
-putbitcaps(uchar *p, uchar *ep)
+static int
+putbitcaps(uchar *p, uint nb, Caps* caps)
{
- if(p+30>ep)
- sysfatal(Eshort);
+ if(nb < 30){
+ werrstr(Eshort);
+ return -1;
+ }
PSHORT(p+0, CapBitmap);
- PSHORT(p+2, BITCAPSIZE);
- PSHORT(p+4, rd.depth); // preferredBitsPerPixel
+ PSHORT(p+2, 30); // size
+ PSHORT(p+4, caps->depth); // preferredBitsPerPixel
PSHORT(p+6, 1); // receive1BitPerPixel
PSHORT(p+8, 1); // receive4BitsPerPixel
PSHORT(p+10, 1); // receive8BitsPerPixel
- PSHORT(p+12, rd.dim.x); // desktopWidth
- PSHORT(p+14, rd.dim.y); // desktopHeight
+ PSHORT(p+12, caps->xsz); // desktopWidth
+ PSHORT(p+14, caps->ysz); // desktopHeight
PSHORT(p+16, 0); // pad2octets
PSHORT(p+18, 1); // desktopResizeFlag
PSHORT(p+20, 1); // bitmapCompressionFlag
@@ -114,12 +197,12 @@
PSHORT(p+24, 1); // drawingFlags
PSHORT(p+26, 1); // multipleRectangleSupport
PSHORT(p+26, 0); // pad2octetsB
- return p+30;
+ return 30;
}
/* 2.2.7.1.3 Order Capability Set (TS_ORDER_CAPABILITYSET) */
-uchar*
-putordcaps(uchar *p, uchar *ep)
+static int
+putordcaps(uchar *p, uint nb, Caps*)
{
ushort orderFlags;
enum
@@ -135,11 +218,13 @@
| ZEROBOUNDSDELTASSUPPORT
| COLORINDEXSUPPORT
| SOLIDPATTERNBRUSHONLY
- ;
- if(p+88>ep)
- sysfatal(Eshort);
+ ;
+ if(nb<88){
+ werrstr(Eshort);
+ return -1;
+ }
PSHORT(p+0, CapOrder);
- PSHORT(p+2, ORDCAPSIZE);
+ PSHORT(p+2, 88); // size
memset(p+4, 16, 0); // terminalDescriptor
PLONG(p+20, 0); // pad4octetsA
PSHORT(p+24, 1); // desktopSaveXGranularity
@@ -157,18 +242,20 @@
PSHORT(p+82, 0); // pad2octetsD
PSHORT(p+84, 0xe4); // textANSICodePage
PSHORT(p+86, 0x04); // pad2octetsE
- return p+88;
+ return 88;
}
/* 2.2.7.1.4 Bitmap Cache Capability Set (TS_BITMAPCACHE_CAPABILITYSET) */
/* 2.2.7.1.4.2 Revision 2 (TS_BITMAPCACHE_CAPABILITYSET_REV2) */
-uchar*
-putbc2caps(uchar *p, uchar *ep)
+static int
+putbc2caps(uchar *p, uint nb, Caps*)
{
- if(p+40>ep)
- sysfatal(Eshort);
+ if(nb<40){
+ werrstr(Eshort);
+ return -1;
+ }
PSHORT(p+0, CapBitcache2);
- PSHORT(p+2, BCACAPSIZE);
+ PSHORT(p+2, 40); // size
PSHORT(p+4, 0); // CacheFlags (2 bytes):
p[6] = 0; // pad2
p[7] = 3; // NumCellCaches
@@ -178,25 +265,27 @@
PLONG(p+20, 0); // BitmapCache3CellInfo
PLONG(p+24, 0); // BitmapCache4CellInfo
memset(p+28, 12, 0); // Pad3
- return p+40;
+ return 40;
}
/* 2.2.7.1.5 Pointer Capability Set (TS_POINTER_CAPABILITYSET) */
-uchar*
-putptrcaps(uchar *p, uchar *ep)
+static int
+putptrcaps(uchar *p, uint nb, Caps*)
{
- if(p+8>ep)
- sysfatal(Eshort);
+ if(nb<8){
+ werrstr(Eshort);
+ return -1;
+ }
PSHORT(p+0, CapPointer);
- PSHORT(p+2, PTRCAPSIZE);
+ PSHORT(p+2, 8); // size
PSHORT(p+4, 0); // colorPointerFlag
PSHORT(p+6, 20); // colorPointerCacheSize
- return p+8;
+ return 8;
}
/* 2.2.7.1.6 Input Capability Set (TS_INPUT_CAPABILITYSET) */
-uchar*
-putinpcaps(uchar *p, uchar *ep)
+static int
+putinpcaps(uchar *p, uint nb, Caps*)
{
long inputFlags;
enum
@@ -209,14 +298,15 @@
};
inputFlags = 0
- | INPUT_FLAG_SCANCODES
- | INPUT_FLAG_UNICODE
- ;
-
- if(p+88>ep)
- sysfatal(Eshort);
+ | INPUT_FLAG_SCANCODES
+ | INPUT_FLAG_UNICODE
+ ;
+ if(nb<88){
+ werrstr(Eshort);
+ return -1;
+ }
PSHORT(p+0, CapInput);
- PSHORT(p+2, INPCAPSIZE);
+ PSHORT(p+2, 88); // size
PSHORT(p+4, inputFlags); // inputFlags
PSHORT(p+6, 0); // pad2octetsA
@@ -226,21 +316,23 @@
PLONG(p+16, 0); // keyboardSubType
PLONG(p+20, 12); // keyboardFunctionKey
memset(p+24, 64, 0); // imeFileName
- return p+88;
+ return 88;
}
/* 2.2.7.1.8 Glyph Cache Capability Set (TS_GLYPHCACHE_CAPABILITYSET) */
-uchar*
-putglycaps(uchar* p, uchar* ep)
+static int
+putglycaps(uchar *p, uint nb, Caps*)
{
enum {
GLYPH_SUPPORT_NONE= 0,
};
- if(p+52>ep)
- sysfatal(Eshort);
+ if(nb<52){
+ werrstr(Eshort);
+ return -1;
+ }
PSHORT(p+0, CapGlyph);
- PSHORT(p+2, GLYCAPSIZE);
+ PSHORT(p+2, 52); // size
PLONG(p+4, 0x0400fe); // GlyphCache 0
PLONG(p+8, 0x0400fe); // GlyphCache 1
PLONG(p+12, 0x0800fe); // GlyphCache 2
@@ -254,18 +346,20 @@
PLONG(p+44, 0x01000100); // FragCache
PSHORT(p+48, GLYPH_SUPPORT_NONE); // GlyphSupportLevel
PSHORT(p+50, 0); // pad2octets
- return p+52;
+ return 52;
}
/* 2.2.7.1.11 Sound Capability Set (TS_SOUND_CAPABILITYSET) */
-uchar*
-putsndcaps(uchar* p, uchar* ep)
+static int
+putsndcaps(uchar *p, uint nb, Caps*)
{
- if(p+8>ep)
- sysfatal(Eshort);
+ if(nb<8){
+ werrstr(Eshort);
+ return -1;
+ }
PSHORT(p+0, CapSound);
- PSHORT(p+2, SNDCAPSIZE);
+ PSHORT(p+2, 8); // size
PSHORT(p+4, 0); // soundFlags
PSHORT(p+6, 0); // pad2octetsA
- return p+8;
+ return 8;
}
--- a/dat.h
+++ b/dat.h
@@ -1,6 +1,9 @@
typedef struct Rdp Rdp;
typedef struct Vchan Vchan;
-typedef struct Rdpnego Rdpnego;
+typedef struct Msg Msg;
+typedef struct Share Share;
+typedef struct Caps Caps;
+typedef struct Imgupd Imgupd;
#define GSHORT(p) ((p)[0]|((p)[1]<<8))
#define GSHORTB(p) ((p)[0]<<8|((p)[1]))
@@ -13,71 +16,237 @@
#define MIN(x,y) (((x) < (y)) ? (x) : (y))
+enum
+{
+ MAXTPDU= 16386, /* max TPDU size */
+};
+
struct Rdp
{
int fd; /* connection I/O descriptor */
- long sproto; /* server-selected security protocol to replay back */
- int autologon; /* enable auto logon */
+ long sproto; /* magic to bounce back to server */
char *label; /* window label */
char *local; /* local system name */
- char *user; /* user name */
+ char *user; /* user name for auto logon */
char *windom; /* domain for auto logon */
char *passwd; /* password for auto logon (sic) */
char *shell; /* remote shell override */
char *rwd; /* remote working directory */
+ int xsz; /* rfb dimensions */
+ int ysz; /* rfb dimensions */
+ int depth; /* rfb color depth */
ulong chan; /* remote graphics channel descriptor */
- int depth; /* color depth as exposed by the protocol */
int hupreason; /* hangup reason as server explains */
int mcsuid; /* MCS [T.122] userId */
int userchan; /* MCS user channelId */
+ int srvchan; /* MCS server channel ID */
int shareid; /* share ID - [T128] section 8.4.2 */
- int licensed; /* licensing sub-protocol completion */
int active; /* T.128 action state */
int wantconsole; /* attach to the console sesstion */
- Point dim; /* rfb size */
+ Vchan *vc; /* static virtual channels table */
+ uint nvc; /* number of vctab entries */
+ uchar cmap[256]; /* rfb color map for depths ≤ 8 */
+ uchar rbuf[MAXTPDU]; /* read buffer */
};
+int starttls(Rdp*);
+int rdphandshake(Rdp*);
+int x224connect(Rdp*);
+int x224disconnect(Rdp*);
+void sendclientinfo(Rdp*);
+void confirmactive(Rdp*);
+void assync(Rdp*);
+void asctl(Rdp*,int);
+void asfontls(Rdp*);
+void passinput(Rdp*,ulong,int,int,int,int);
+void turnupdates(Rdp*, int);
+void erectdom(Rdp*);
+void readnet(Rdp*);
+void clipannounce(Rdp*);
+void clipvcfn(Rdp*, uchar*,uint);
+void pollsnarf(Rdp*);
+void readkbd(Rdp*);
+void readdevmouse(Rdp*);
+void eresized(Rdp*, int);
+
+
struct Vchan
{
int mcsid; /* MCS channelId */
int flags;
char name[8];
- int defragging;
- uchar* buf; /* defragmentation buffer */
+ uchar *buf; /* defragmentation buffer */
int nb; /* sizeof buf */
int pos; /* next fragment offset */
- void (*fn)(uchar*,uchar*);
+ void (*fn)(Rdp*,uchar*,uint);
};
-Vchan* lookupvc(int);
-Vchan* namevc(char*);
-int sendvc(char*,uchar*,int);
-void scanvcpdu(uchar*,uchar*,int);
+void initvc(Rdp*);
+int sendvc(Rdp*,char*,uchar*,int);
-enum
+struct Caps
{
- /* 2.2.7 Capability Sets; T.128 */
- CapGeneral= 1,
- CapBitmap= 2,
- CapOrder= 3,
- CapPointer= 8,
- CapBitcache2= 19,
- CapInput= 13,
- CapSound= 12,
- CapGlyph= 16,
- GENCAPSIZE= 24,
- BITCAPSIZE= 30,
- ORDCAPSIZE= 88,
- BCACAPSIZE= 40,
- PTRCAPSIZE= 8,
- INPCAPSIZE= 88,
- SNDCAPSIZE= 8,
- GLYCAPSIZE= 52,
+ int general;
+ int canrefresh;
+ int cansupress;
- /* 2.2.7.1.1 General Capability Set (TS_GENERAL_CAPABILITYSET) */
- CanFastpath = 0x0001,
- NoBitcomphdr = 0x0400,
- CanLongcred = 0x0004,
+ int bitmap;
+ int depth;
+ int xsz;
+ int ysz;
+};
+int getcaps(Caps*,uchar*,uint);
+int sizecaps(Caps*);
+int putcaps(uchar*,uint,Caps*);
+enum /* Msg.type */
+{
+ Xconnect=1, /* C: X.224 connect request */
+ Xconnected, /* S: X.224 connection confirm */
+ Xhangup, /* C: X.224 disconnection request */
+ Mattach, /* C: MCS (T.125) Attach User Request */
+ Mattached, /* S: MCS Attach User Confirm */
+ Mjoin, /* C: MCS Channel Join Request */
+ Mjoined, /* S: MCS Channel Join Confirm */
+ Merectdom, /* C: MCS Erect Domain Request */
+ Mconnect, /* C: MCS Connect Initial + GCC Confce Create Req */
+ Mconnected, /* S: MCS Connect Response + GCC Confce Create Resp */
+ Mactivated, /* C: MCS Confirm Active */
+ Mclosing, /* S: Disconnect Provider Ultimatum */
+ Aflow, /* S: T.128 Flow PDU */
+ Async, /* C: MPAS 2.2.1.14 Client Synchronize PDU */
+ Actl, /* C: MPAS 2.2.1.15 Control PDU */
+ Afontls, /* C: MPAS 2.2.1.18 Client Font List PDU */
+ Ainput, /* C: MPAS (T.128) Input Event */
+ Dclientinfo, /* C: RDP 2.2.1.11 Client Info */
+ Dsupress, /* C: RDP 2.2.11.3 Suppress Output PDU */
+ Lneedlicense, /* S: Licensing PDU */
+ Lreq, /* C: Licensing PDU */
+ Lhavechal, /* S: Licensing PDU */
+ Lnolicense, /* C: Licensing PDU */
+ Ldone, /* S: Licensing PDU */
+ Aupdate, /* S: T.128 ASPDU or a "Fast-Path" RDP PDU */
+ Mvcdata, /* S,C: MCS virtual channel data, raw */
+};
+
+enum /* Msg.negproto - for msg.c x224.c */
+{
+ ProtoTLS= 1,
+ ProtoCSSP= 2,
+ ProtoUAUTH= 8,
+};
+
+struct Msg {
+ int type;
+ int negproto; /* Xconnect, Xconnected */
+ int mcsuid; /* Mattached, Mjoin, Mactivated, Async & more */
+ int chanid; /* Mjoin, Mvcdata */
+ int originid; /* Mactivated, Async, Actl, Afontls, Ainput, Dsupress */
+ int shareid; /* Mactivated, Async, Actl, Afontls, Ainput, Dsupress */
+ int ver; /* Mconnect, Mconnected */
+ int xsz; /* Mconnect, Dsupress, Mactivated */
+ int ysz; /* Mconnect, Dsupress, Mactivated */
+ int height; /* Mconnect, Dsupress, Mactivated */
+ char *sysname; /* Mconnect, Dclientinfo, Lreq */
+ int sproto; /* Mconnect */
+ int wantconsole; /* Mconnect */
+ uint nvc; /* Mconnect */
+ Vchan *vctab; /* Mconnect */
+ char *dom; /* Dclientinfo*/
+ char *user; /* Dclientinfo, Lreq */
+ char *pass; /* Dclientinfo */
+ char *rshell; /* Dclientinfo */
+ char *rwd; /* Dclientinfo */
+ int dologin; /* Dclientinfo */
+ int mtype; /* Ainput */
+ ulong msec; /* Ainput */
+ ulong flags; /* Ainput, Mvcdata */
+ int iarg1; /* Ainput */
+ int iarg2; /* Ainput */
+ int action; /* Actl */
+ int allow; /* Dsupress */
+ uchar* data; /* Mvcdata, Aupdate */
+ uint ndata; /* Mvcdata, Aupdate */
+ uint len; /* Mvcdata */
+ int (*getshare)(Share*, uchar*, uint); /* Aupdate */
+};
+
+typedef int Msgget(Msg*,uchar*,uint);
+typedef int Msgput(uchar*,uint,Msg*);
+
+Msgget getmsg;
+Msgput putmsg;
+int readmsg(Rdp*,Msg*);
+int writemsg(Rdp*,Msg*);
+
+int sizegccr(Msg*);
+Msgget getmcr;
+Msgput putgccr;
+Msgput putclientinfo;
+Msgput putconfirmactive;
+
+int sizelicensemsg(Msg*);
+Msgget getlicensemsg;
+Msgput putlicensemsg;
+void respondlicense(Rdp*,Msg*);
+
+void scanvcdata(Rdp*, Msg*);
+void scanupdates(Rdp*, Msg*);
+
+enum /* Share.type */
+{
+ ShActivate= 1,
+ ShDeactivate,
+ ShUorders,
+ ShUimg,
+ ShUcmap,
+ ShUwarp,
+ ShSync,
+ ShCtl,
+ ShFmap,
+ ShEinfo,
+};
+
+struct Share
+{
+ int type;
+ int source;
+ int shareid;
+ int ncap;
+ int nord;
+ int nrect;
+ int x;
+ int y;
+ int err;
+ uchar* data;
+ uint ndata;
+};
+int getshareT(Share*, uchar*, uint); /* T.128 ASPDU updates */
+int getshareF(Share*, uchar*, uint); /* RDP Fast-Path updates */
+
+void activating(Rdp*,Share*);
+void deactivating(Rdp*,Share*);
+void scanimgupdate(Rdp*,Share*);
+void scancmap(Rdp*,Share*);
+void scanorders(Rdp*,Share*);
+
+
+struct Imgupd {
+ int x;
+ int y;
+ int xm;
+ int ym;
+ int xsz;
+ int ysz;
+ int depth;
+ int iscompr;
+ int nbytes;
+ uchar* bytes;
+};
+int getimgupd(Imgupd*, uchar*, uint);
+
+
+enum
+{
/* 2.2.8.1.1.2.1 Basic (TS_SECURITY_HEADER) */
Scrypt = 0x0008,
Sinfopk = 0x0040,
@@ -89,23 +258,63 @@
InputUnicode= 5,
InputMouse= 0x8001,
+ /* 2.2.1.15.1 Control PDU Data */
+ CAreqctl= 1,
+ CAcooperate= 4,
+
+ GLOBALCHAN= 1003, /* MCS global channel id */
+
TPKTFIXLEN= 4,
TPDATAFIXLEN= (TPKTFIXLEN+3),
MCSCIFIXLEN= (18+3*2+24*4),
- MAXTPDU= 16386, /* max TPDU size */
- SRVCHAN= 1002, /* server channel ID */
- GLOBALCHAN= 1003, /* MCS global channel's id */
+ SECHSIZE= 4,
+ SCHSIZE= 6,
+ SCDSIZE= SCHSIZE+4+4+2*2,
+
NumOrders= 32,
};
-extern Rdp rd;
extern uchar orderSupport[NumOrders];
-extern uchar cmap[256]; /* 8bpp translation table */
-extern Vchan vctab[]; /* static virtual channels table */
-extern uint nvc; /* number of vctab entries */
-
extern char Eshort[];
extern char Ebignum[];
extern char Esmall[];
+
+
+enum /* X.224 PDU codes */
+{
+ ConReq= 0xE0, /* connection request */
+ ConCfrm= 0xD0, /* connection confirm */
+ HupReq= 0x80, /* disconnection request */
+ Data= 0xF0, /* data */
+ Err= 0x70, /* error */
+};
+
+enum /* ASN.1 tag numbers for MCS types */
+{
+ Mci= 101, /* Connect Initial */
+ Mcr= 102, /* Connect Response */
+ Medr= 1, /* Erect Domain Request */
+ Maur= 10, /* Attach User Request */
+ Mauc= 11, /* Attach User Confirm */
+ Mcjr= 14, /* Channel Join Request */
+ Mcjc= 15, /* Channel Join Confirm */
+ Msdr= 25, /* Send Data Request */
+ Msdi= 26, /* Send Data Indication */
+ Mdpu= 8, /* Disconnect Provider Ultimatum */
+};
+
+enum /* 2.2.8.1.1.1.2 Share Data Header (TS_SHAREDATAHEADER) */
+{
+ ADdraw= 2,
+ ADctl= 20,
+ ADcursor= 27,
+ ADinput= 28,
+ ADsync= 31,
+ ADrefresh= 33,
+ ADsupress= 35,
+ ADfontlist= 39,
+ ADfontmap= 40,
+ ADerrx= 47,
+};
--- a/eclip.c
+++ b/eclip.c
@@ -12,26 +12,19 @@
#include "fns.h"
static char cliprdr[] = "CLIPRDR";
-static void cliprequest(uint);
enum
{
- CFunicode = 13,
-};
+ CFunicode= 13,
-enum
-{
- FlagOk = (1<<0),
- FlagErr = (1<<1),
-};
+ FlagOk= (1<<0),
+ FlagErr= (1<<1),
-enum
-{
- ClipReady = 1,
- ClipAnnounce = 2,
- ClipNoted = 3,
- ClipReq = 4,
- ClipResp = 5,
+ ClipReady= 1,
+ ClipAnnounce= 2,
+ ClipNoted= 3,
+ ClipReq= 4,
+ ClipResp= 5,
};
typedef struct Clipmsg Clipmsg;
@@ -43,16 +36,15 @@
uchar *data;
uint ndata;
};
-
static int clipputmsg(Clipmsg*,uchar*,int);
static int clipgetmsg(Clipmsg*,uchar*,int);
-static void clipattached(Clipmsg*);
-static void clipnoted(Clipmsg*);
-static void cliprequested(Clipmsg*);
-static void clipprovided(Clipmsg*);
+static void clipattached(Rdp*,Clipmsg*);
+static void clipnoted(Rdp*,Clipmsg*);
+static void cliprequested(Rdp*,Clipmsg*);
+static void clipprovided(Rdp*,Clipmsg*);
-static void (*clipcall[])(Clipmsg*) =
+static void (*clipcall[])(Rdp*,Clipmsg*) =
{
[ClipReady]= clipattached,
[ClipAnnounce]= clipnoted,
@@ -60,12 +52,14 @@
[ClipResp]= clipprovided,
};
+static void cliprequest(Rdp*,uint);
+
void
-clipvcfn(uchar* p, uchar* ep)
+clipvcfn(Rdp* c, uchar* p, uint nb)
{
Clipmsg tx;
- if(clipgetmsg(&tx, p, ep-p) < 0)
+ if(clipgetmsg(&tx, p, nb) < 0)
return;
if(tx.flags&FlagErr)
return;
@@ -73,11 +67,11 @@
return;
if(clipcall[tx.type] == nil)
return;
- clipcall[tx.type](&tx);
+ clipcall[tx.type](c, &tx);
}
void
-clipannounce(void)
+clipannounce(Rdp* c)
{
Clipmsg r;
uchar a[44];
@@ -87,12 +81,12 @@
r.flags = 0;
r.fmtid = CFunicode;
n = clipputmsg(&r, a, sizeof(a));
- if(sendvc(cliprdr, a, n) < 0)
+ if(sendvc(c, cliprdr, a, n) < 0)
fprint(2, "clipannounce: %r\n");
}
static void
-cliprequest(uint fmtid)
+cliprequest(Rdp* c, uint fmtid)
{
Clipmsg r;
uchar a[12];
@@ -102,18 +96,18 @@
r.flags = 0;
r.fmtid = fmtid;
n = clipputmsg(&r, a, sizeof(a));
- if(sendvc(cliprdr, a, n) < 0)
+ if(sendvc(c, cliprdr, a, n) < 0)
fprint(2, "cliprequest: %r\n");
}
static void
-clipattached(Clipmsg*)
+clipattached(Rdp* c, Clipmsg*)
{
- clipannounce();
+ clipannounce(c);
}
static void
-clipnoted(Clipmsg *m)
+clipnoted(Rdp* c, Clipmsg *m)
{
Clipmsg r;
uchar a[8];
@@ -120,17 +114,17 @@
int n;
if(m->fmtid)
- cliprequest(m->fmtid);
+ cliprequest(c, m->fmtid);
r.type = ClipNoted;
r.flags = FlagOk;
n = clipputmsg(&r, a, sizeof(a));
- if(sendvc(cliprdr, a, n) < 0)
+ if(sendvc(c, cliprdr, a, n) < 0)
fprint(2, "clipnoted: %r\n");
}
static void
-cliprequested(Clipmsg *m)
+cliprequested(Rdp* c, Clipmsg *m)
{
Clipmsg r;
char* s;
@@ -158,13 +152,13 @@
r.data = b+8;
r.ndata = nb;
n = clipputmsg(&r, b, nb+8);
- if(sendvc(cliprdr, b, n) < 0)
+ if(sendvc(c, cliprdr, b, n) < 0)
fprint(2, "cliprequested: %r\n");
free(b);
}
static void
-clipprovided(Clipmsg *m)
+clipprovided(Rdp*, Clipmsg *m)
{
char *s;
int n, ns;
--- a/egdi.c
+++ b/egdi.c
@@ -85,14 +85,14 @@
struct Order
{
int fsize;
- uchar* (*fn)(uchar*,uchar*,int,int);
+ uchar* (*fn)(Rdp*, uchar*,uchar*,int,int);
};
-static uchar* scrblt(uchar*,uchar*,int,int);
-static uchar* memblt(uchar*,uchar*,int,int);
-static uchar* cacheimage2(uchar*,uchar*,int,int);
-static uchar* cacheimage(uchar*,uchar*,int,int);
-static uchar* cachecmap(uchar*,uchar*,int,int);
+static uchar* scrblt(Rdp*, uchar*,uchar*,int,int);
+static uchar* memblt(Rdp*, uchar*,uchar*,int,int);
+static uchar* cacheimage2(Rdp*, uchar*,uchar*,int,int);
+static uchar* cacheimage(Rdp*, uchar*,uchar*,int,int);
+static uchar* cachecmap(Rdp*, uchar*,uchar*,int,int);
Order ordtab[NumOrders] = {
[ScrBlt]= { 1, scrblt },
@@ -132,11 +132,17 @@
/* 2.2.2.2 Fast-Path Orders Update (TS_FP_UPDATE_ORDERS) */
void
-scanorders(uchar* p, uchar* ep, int count)
+scanorders(Rdp* c, Share* as)
{
+ int count;
+ uchar *p, *ep;
int ctl, fmask, fsize;
int size, opt, xorder;
+ count = as->nord;
+ p = as->data;
+ ep = as->data + as->ndata;
+
while(count-- > 0 && p<ep){
fmask = 0;
ctl = *p;
@@ -144,10 +150,10 @@
goto ErrNstd; // GDI+ or out of sync
if(ctl&Secondary){
if(p+6>ep)
- sysfatal(Eshort);
+ sysfatal("scanorders: %s", Eshort);
size = ((short)GSHORT(p+1))+13;
if(size < 0 || p+size > ep)
- sysfatal(Eshort);
+ sysfatal("scanorders: size: %s", Eshort);
opt = GSHORT(p+3);
xorder = p[5];
if(xorder >= nelem(auxtab) || auxtab[xorder].fn == nil){
@@ -156,7 +162,7 @@
continue;
}
- auxtab[xorder].fn(p, p+size, xorder, opt);
+ auxtab[xorder].fn(c, p, p+size, xorder, opt);
p += size;
continue;
}
@@ -188,7 +194,7 @@
if(ordtab[gc.order].fn == nil)
goto ErrNotsup;
- p = ordtab[gc.order].fn(p, ep, ctl, fmask);
+ p = ordtab[gc.order].fn(c, p, ep, ctl, fmask);
if(p == nil)
break;
}
@@ -239,7 +245,7 @@
p += 2;
}
if(p>ep)
- sysfatal(Eshort);
+ sysfatal("getclipr: %s", Eshort);
return p;
}
@@ -265,7 +271,7 @@
};
}
if(s > es)
- sysfatal(Eshort);
+ sysfatal("getpt: %s", Eshort);
*pp = p;
return s;
}
@@ -285,7 +291,7 @@
/* 2.2.2.2.1.1.2.7 ScrBlt (SCRBLT_ORDER) */
static uchar*
-scrblt(uchar* p, uchar* ep, int ctl, int fmask)
+scrblt(Rdp*, uchar* p, uchar* ep, int ctl, int fmask)
{
static Rectangle r;
static Point pt;
@@ -317,7 +323,7 @@
/* 2.2.2.2.1.1.2.9 MemBlt (MEMBLT_ORDER) */
static uchar*
-memblt(uchar* p, uchar* ep, int ctl, int fmask)
+memblt(Rdp*, uchar* p, uchar* ep, int ctl, int fmask)
{
static int cid; /* cacheId */
static int coff; /* cacheIndex */
@@ -339,7 +345,7 @@
p += 2;
}
if(p>ep)
- sysfatal(Eshort);
+ sysfatal("memblt: %s", Eshort);
cid &= Bits8;
if(cid >= nelem(imgcache) || coff >= nelem(*imgcache)){
@@ -387,7 +393,7 @@
/* 2.2.2.2.1.2.2 Cache Bitmap - Revision 1 (CACHE_BITMAP_ORDER) */
static uchar*
-cacheimage(uchar* p, uchar* ep, int xorder, int opt)
+cacheimage(Rdp* c, uchar* p, uchar* ep, int xorder, int opt)
{
int cid; /* cacheId */
int coff; /* cacheIndex */
@@ -400,7 +406,7 @@
Rectangle r;
if(p+15 >= ep)
- sysfatal(Eshort);
+ sysfatal("cacheimage: %s", Eshort);
cid = p[6];
d.x = p[8];
d.y = p[9];
@@ -408,7 +414,7 @@
coff = GSHORT(p+13);
r.min = ZP;
r.max = d;
- chan = rd.chan;
+ chan = c->chan;
zip = (xorder==CacheCompressed);
if(zip)
@@ -417,10 +423,10 @@
size -= 8;
}
if(p+size > ep)
- sysfatal(Eshort);
+ sysfatal("cacheimage: size: %s", Eshort);
if((img = pickimage(cid, coff, r, chan)) == nil)
sysfatal("pickimage: %r");
- err = (zip? loadrle : loadbmp)(img, r, p, size);
+ err = (zip? loadrle : loadbmp)(img, r, p, size, c->cmap);
if(err < 0)
sysfatal("%r");
return p+size;
@@ -428,9 +434,9 @@
/* 2.2.2.2.1.2.3 Cache Bitmap - Revision 2 (CACHE_BITMAP_REV2_ORDER) */
static uchar*
-cacheimage2(uchar* p,uchar* ep, int xorder, int opt)
+cacheimage2(Rdp* c, uchar* p,uchar* ep, int xorder, int opt)
{
- int n, c;
+ int n, g;
int zip;
int cid; /* cacheId */
int coff; /* cacheIndex */
@@ -442,10 +448,10 @@
Rectangle r;
if(p+9 >= ep)
- sysfatal(Eshort);
+ sysfatal("cacheimage2: %s", Eshort);
p += 6;
- chan = rd.chan;
+ chan = c->chan;
zip = (xorder==CacheCompressed2);
cid = opt&Bits3;
opt >>= 7;
@@ -452,35 +458,36 @@
if(opt&1<<1)
p += 8; // persistent cache key
- c = *p++;
- if(c&1<<7)
- c = ((c&Bits7)<<8) | *p++;
- d.x = c;
+ g = *p++;
+ if(g&1<<7)
+ g = ((g&Bits7)<<8) | *p++;
+ d.x = g;
if(opt&1)
d.y = d.x;
else{
- c = *p++;
- if(c&1<<7)
- c = ((c&Bits7)<<8) | *p++;
- d.y = c;
+ g = *p++;
+ if(g&1<<7)
+ g = ((g&Bits7)<<8) | *p++;
+ d.y = g;
}
r.min = ZP;
r.max = d;
- c = *p++;
- n = c>>6;
- c &= Bits6;
+ g = *p++;
+ n = g>>6;
+ g &= Bits6;
switch(n){
- case 3: c = (c<<8) | *p++;
- case 2: c = (c<<8) | *p++;
- case 1: c = (c<<8) | *p++;
+ default: sysfatal("cacheimage2: integer too big");
+ case 3: g = (g<<8) | *p++;
+ case 2: g = (g<<8) | *p++;
+ case 1: g = (g<<8) | *p++;
}
- size = c; // fixme: protect from integer overflow
+ size = g;
- c = *p++;
- if(c&1<<7)
- c = ((c&Bits7)<<8) | *p++;
- coff = c;
+ g = *p++;
+ if(g&1<<7)
+ g = ((g&Bits7)<<8) | *p++;
+ coff = g;
if(zip&& !(opt&1<<3)){
p += 8; // bitmapComprHdr
@@ -487,10 +494,10 @@
size -= 8;
}
if(p+size > ep)
- sysfatal(Eshort);
+ sysfatal("cacheimage2: size: %s", Eshort);
if((img = pickimage(cid, coff, r, chan)) == nil)
- sysfatal("pullimage: %r");
- err = (zip? loadrle : loadbmp)(img, r, p, size);
+ sysfatal("pickimage: %r");
+ err = (zip? loadrle : loadbmp)(img, r, p, size, c->cmap);
if(err < 0)
sysfatal("%r");
return p+size;
@@ -498,7 +505,7 @@
/* 2.2.2.2.1.2.4 Cache Color Table (CACHE_COLOR_TABLE_ORDER) */
static uchar*
-cachecmap(uchar* p,uchar* ep, int, int)
+cachecmap(Rdp*, uchar* p,uchar* ep, int, int)
{
int cid, n;
--- a/ele.c
+++ b/ele.c
@@ -23,9 +23,7 @@
SHaveChal= 2,
SHaveLicense= 3,
SNeedRenew= 4,
- CLicenseInfo= 0x12,
CNeedLicense= 0x13,
- CChalResp= 0x15,
Notify= 0xFF,
Brandom= 2,
@@ -39,106 +37,118 @@
NoTransition= 2,
};
-static void reqlicense(char*,char*);
-static void senderr(int,int);
-
-void
-scanlicensepdu(uchar* p, uchar* ep)
+int
+getlicensemsg(Msg* m, uchar* b, uint nb)
{
- uchar type;
+ uint type;
- if(ep-p < 1)
+ if(nb < 1)
sysfatal(Eshort);
/* type[1] flags[1] size[2] */
- type = p[0];
+ type = b[0];
switch(type){
+ default:
+ werrstr("unhandled license packet %ud", type);
+ m->type = 0;
+ return -1;
case SNeedLicense:
- reqlicense(rd.user, rd.local);
+ m->type = Lneedlicense;
break;
case SHaveChal:
- fprint(2, "unhandled SHaveChal PDU\n");
- senderr(ErrCNoLicense, TotalAbort);
+ m->type = Lhavechal;
break;
case SNeedRenew:
case SHaveLicense:
case Notify:
- rd.licensed = 1;
+ m->type = Ldone;
break;
}
+ return nb;
}
-static void
-reqlicense(char* user, char *host)
+int
+sizelicensemsg(Msg* m)
{
- uchar buf[180], *p, *ep;
- int nb, ndata, usersize, hostsize;
+ int usersize, hostsize;
- usersize = strlen(user)+1;
- hostsize = strlen(host)+1;
- ndata = 24+usersize+hostsize+RandomSize+48;
- nb = sizeof(buf);
+ switch(m->type){
+ default:
+ werrstr("sizelicensemsg: bad message type");
+ return -1;
+ case Lreq:
+ usersize = strlen(m->user)+1;
+ hostsize = strlen(m->sysname)+1;
+ return 24+usersize+hostsize+RandomSize+48;
+ break;
+ case Lnolicense:
+ return 16;
+ }
+}
- p = prebuf(buf, nb, ndata, 0, Slicensepk);
- if(p == nil)
- sysfatal("reqlicense: %r");
- ep = p+ndata;
+int
+putlicensemsg(uchar* buf, uint nb, Msg* m)
+{
+ uchar *p, *ep;
+ int ndata, usersize, hostsize;
+ int errcode, newstate;
- /*
- * type[1] flags[1] size[2]
- * kexalg[4] platfid[4] crandom[32]
- * premaster[blob] cuser[blob] chost[blob]
- *
- * blob := type[2] len[2] data[len]
- */
- p[0] = CNeedLicense;
- p[1] = PreambleV3;
- PSHORT(p+2, ndata);
+ p = buf;
+ ep = buf+nb;
+ ndata = nb;
- PLONG(p+4, KeyExRSA);
- PLONG(p+8, 0);
- memset(p+12, RandomSize, 0);
- p += 12+RandomSize;
+ switch(m->type){
+ default:
+ werrstr("putlicensemsg: bad message type");
+ return -1;
+ case Lreq:
+ usersize = strlen(m->user)+1;
+ hostsize = strlen(m->sysname)+1;
- PSHORT(p+0, Brandom);
- PSHORT(p+2, 48);
- memset(p+4, 48, 0);
- p += 4+48;
+ /*
+ * type[1] flags[1] size[2] kexalg[4] platfid[4] crandom[32]
+ * premaster[blob] cuser[blob] chost[blob]
+ * (blob := type[2] len[2] data[len])
+ */
+ p[0] = CNeedLicense;
+ p[1] = PreambleV3;
+ PSHORT(p+2, ndata);
+ PLONG(p+4, KeyExRSA);
+ PLONG(p+8, 0);
+ memset(p+12, RandomSize, 0);
+ p += 12+RandomSize;
+
+ PSHORT(p+0, Brandom);
+ PSHORT(p+2, 48);
+ memset(p+4, 48, 0);
+ p += 4+48;
- PSHORT(p+0, Bcuser);
- PSHORT(p+2, usersize);
- memcpy(p+4, user, usersize);
- p+= 4+usersize;
+ PSHORT(p+0, Bcuser);
+ PSHORT(p+2, usersize);
+ memcpy(p+4, m->user, usersize);
+ p+= 4+usersize;
+
+ PSHORT(p+0, Bchost);
+ PSHORT(p+2, hostsize);
+ memcpy(p+4, m->sysname, hostsize);
+ p+= 4+hostsize;
+ break;
- PSHORT(p+0, Bchost);
- PSHORT(p+2, hostsize);
- memcpy(p+4, host, hostsize);
- p+= 4+hostsize;
+ case Lnolicense:
+ errcode = ErrCNoLicense;
+ newstate = TotalAbort;
+ /* type[1] flags[1] size[2] errcode[4] newstate[4] blob.type[2] blob.len[2] ... */
+ p[0] = Notify;
+ p[1] = PreambleV3;
+ PSHORT(p+2, ndata);
+ PLONG(p+4, errcode);
+ PLONG(p+8, newstate);
+ PSHORT(p+12, Berror);
+ PSHORT(p+14, 0);
+ break;
+ }
assert(p == ep);
- writen(rd.fd, buf, p-buf);
+ return p-buf;
}
-static void
-senderr(int errcode, int newstate)
-{
- uchar buf[512], *p;
- int nb, ndata;
-
- nb = sizeof(buf);
- ndata = 16;
- p = prebuf(buf, nb, ndata, 0, Slicensepk);
- if(p == nil)
- sysfatal("prebuf: %r");
-
- /* type[1] flags[1] size[2] errcode[4] newstate[4] blob.type[2] blob.len[2] */
- p[0] = Notify;
- p[1] = PreambleV3;
- PSHORT(p+2, ndata);
- PLONG(p+4, errcode);
- PLONG(p+8, newstate);
- PSHORT(p+12, Berror);
- PSHORT(p+14, 0);
-
- writen(rd.fd, buf, p-buf);
-}
--- a/fns.h
+++ b/fns.h
@@ -1,71 +1,28 @@
-/* cap.c */
-void scangencaps(uchar*,uchar*);
-void scanbitcaps(uchar*,uchar*);
-uchar* putgencaps(uchar*,uchar*);
-uchar* putbitcaps(uchar*,uchar*);
-uchar* putordcaps(uchar*,uchar*);
-uchar* putbc2caps(uchar*,uchar*);
-uchar* putptrcaps(uchar*,uchar*);
-uchar* putinpcaps(uchar*,uchar*);
-uchar* putsndcaps(uchar*,uchar*);
-uchar* putglycaps(uchar*,uchar*);
-
/* load.c */
-int loadbmp(Image*,Rectangle,uchar*,int);
-int loadrle(Image*,Rectangle,uchar*,int);
+int loadbmp(Image*,Rectangle,uchar*,int,uchar*);
+int loadrle(Image*,Rectangle,uchar*,int,uchar*);
/* mcs.c */
-int mcschanid(uchar*,uchar*);
+int mcschan(uchar*,uchar*);
int mcstype(uchar*,uchar*);
int ismcshangup(uchar*,uchar*);
-uchar* mcspayload(uchar*,uchar*);
+uchar* mcsdat(uchar*,uchar*);
int mkmcsci(uchar*, int, int);
-int mkmcssdr(uchar*,int,int,int);
-int mcsconnect(int);
-void erectdom(int);
-int attachuser(int);
-int joinchannel(int,int);
+int putmsdr(uchar*,int,int,int,int);
/* mpas.c */
-int rdphandshake(int);
-void readnet(int);
int isflowpdu(uchar*,uchar*);
-void scanaspdu(uchar*, uchar*);
-void scandatapdu(uchar*,uchar*);
-void activating(uchar*,uchar*);
-void passinput(ulong,int,int,int,int);
-void turnupdates(int);
int sizesechdr(int);
-uchar* prebuf(uchar*,int,int,int,int);
+uchar* txprep(uchar*,int,int,int,int,int);
-/* draw.c */
-void eresized(int);
-
-/* eclip.c */
-void clipannounce(void);
-void clipvcfn(uchar*,uchar*);
-
-/* egdi.c */
-void scanorders(uchar*,uchar*,int);
-
-/* ele.c */
-void scanlicensepdu(uchar*,uchar*);
-
/* snarf.c */
void initsnarf(void);
-void pollsnarf(void);
char* getsnarf(int*);
void putsnarf(char*,int);
/* mouse.c */
-void readdevmouse(void);
void warpmouse(int,int);
-/* kbd.c */
-void readkbd(void);
-
-/* sec.c */
-
/* mppc.c */
uchar* uncomp(uchar*,int,int,int*);
@@ -82,12 +39,9 @@
int mktpcr(uchar*,int,int);
int mktpdr(uchar*,int,int);
int istpkt(uchar*,uchar*);
-int tpdutype(uchar*,uchar*);
-int isdatatpdu(uchar*,uchar*);
-uchar* tpdupayload(uchar*,uchar*);
-int x224connect(int);
-int x224disconnect(int);
-int starttls(void);
+int tptype(uchar*,uchar*);
+int istpdat(uchar*,uchar*);
+uchar* tpdat(uchar*,uchar*);
/* rd.c */
void atexitkiller(void);
@@ -97,3 +51,8 @@
char* estrdup(char*);
long writen(int,void*,long);
+uchar* gblen(uchar*,uchar*,int*);
+uchar* gbtag(uchar*,uchar*,int*);
+void pbshort(uchar*,int);
+
+uchar* putsdh(uchar*,uchar*,int,int,int,int);
--- a/guide
+++ b/guide
@@ -3,7 +3,7 @@
window -r 2 44 1026 812
kill 5.out | rc
src -s memcpy 5.out
-g
+g rdphandshake
h2d
d2h
dat.h fns.h mkfile /dist/replica/rd.proto
@@ -10,3 +10,13 @@
diff -r . /sys/src/cmd/rd | sed '/^diff/!d; s//cp /'
wc [~_]*.[ch] | sort -rn
/n/dump/2015/0108/386/bin/rd # legacy security
+B *.[ch]
+Edit X!/rd/.*\.[ch]! ,s/scanvcpdu/scanvcdata/g
+hg pull -u
+hg log -vl5
+hg diff
+hg ci -m'move remaining parsing from scanimgupdate to getshare[TF]'
+hg log -vl2
+hg up -rtip
+hg push
+dat.h
\ No newline at end of file
--- a/kbd.c
+++ b/kbd.c
@@ -106,7 +106,7 @@
};
void
-kbdsendscan(int sc, int mod)
+kbdsendscan(Rdp* c, int sc, int mod)
{
long msec;
int f;
@@ -118,25 +118,25 @@
msec = time(nil);
if(mod != 0)
- passinput(msec, InputKeycode, 0, mod, 0);
- passinput(msec, InputKeycode, f|0, sc, 0);
- passinput(msec, InputKeycode, f|KeyUp, sc, 0);
+ passinput(c, msec, InputKeycode, 0, mod, 0);
+ passinput(c, msec, InputKeycode, f|0, sc, 0);
+ passinput(c, msec, InputKeycode, f|KeyUp, sc, 0);
if(mod != 0)
- passinput(msec, InputKeycode, KeyUp, mod, 0);
+ passinput(c, msec, InputKeycode, KeyUp, mod, 0);
}
void
-kbdsendrune(Rune r)
+kbdsendrune(Rdp* c, Rune r)
{
long msec;
msec = time(nil);
- passinput(msec, InputUnicode, 0, r, 0);
- passinput(msec, InputUnicode, KeyUp, r, 0);
+ passinput(c, msec, InputUnicode, 0, r, 0);
+ passinput(c, msec, InputUnicode, KeyUp, r, 0);
}
void
-readkbd(void)
+readkbd(Rdp* c)
{
char buf[256], k[10];
int ctlfd, fd, kr, kn, w;
@@ -164,46 +164,46 @@
if(r < nelem(rune2scan)){
sc = rune2scan[r].sc;
mod = rune2scan[r].mod;
- kbdsendscan(sc, mod);
+ kbdsendscan(c, sc, mod);
continue;
}
switch(r){
case Kins:
- kbdsendscan(Sins, 0);
+ kbdsendscan(c, Sins, 0);
break;
case Kdel:
- kbdsendscan(Sdel, 0);
+ kbdsendscan(c, Sdel, 0);
break;
case Khome:
- kbdsendscan(Shome, 0);
+ kbdsendscan(c, Shome, 0);
break;
case Kend:
- kbdsendscan(Send, 0);
+ kbdsendscan(c, Send, 0);
break;
case Kpgup:
- kbdsendscan(Spgup, 0);
+ kbdsendscan(c, Spgup, 0);
break;
case Kpgdown:
- kbdsendscan(Spgdown, 0);
+ kbdsendscan(c, Spgdown, 0);
break;
case Kup:
- kbdsendscan(Sup, 0);
+ kbdsendscan(c, Sup, 0);
break;
case Kdown:
- kbdsendscan(Sdown,0 );
+ kbdsendscan(c, Sdown,0 );
break;
case Kleft:
- kbdsendscan(Sleft, 0);
+ kbdsendscan(c, Sleft, 0);
break;
case Kright:
- kbdsendscan(Sright, 0);
+ kbdsendscan(c, Sright, 0);
break;
case Kbrk:
exits("interrupt");
break;
case Kprint:
- kbdsendscan(Sprint, 0);
+ kbdsendscan(c, Sprint, 0);
break;
case KF|1:
case KF|2:
@@ -215,16 +215,16 @@
case KF|8:
case KF|9:
case KF|10:
- kbdsendscan(SF1+r-(KF|1), 0);
+ kbdsendscan(c, SF1+r-(KF|1), 0);
break;
case KF|11:
- kbdsendscan(SF11, 0);
+ kbdsendscan(c, SF11, 0);
break;
case KF|12:
- kbdsendscan(SF12, 0);
+ kbdsendscan(c, SF12, 0);
break;
default:
- kbdsendrune(r);
+ kbdsendrune(c, r);
break;
}
}
--- a/load.c
+++ b/load.c
@@ -6,7 +6,7 @@
/* like loadimage(2) but reverses scanline order and translates per cmap */
int
-loadbmp(Image *i, Rectangle r, uchar *data, int ndata)
+loadbmp(Image *i, Rectangle r, uchar *data, int ndata, uchar *cmap)
{
int n, bpl;
uchar *a;
@@ -46,7 +46,7 @@
}
int
-loadrle(Image *i, Rectangle r, uchar *data, int ndata)
+loadrle(Image *i, Rectangle r, uchar *data, int ndata, uchar *cmap)
{
int nb, bpl;
uchar *buf;
@@ -60,7 +60,7 @@
free(buf);
return -1;
}
- if(loadbmp(i, r, buf, nb) < 0){
+ if(loadbmp(i, r, buf, nb, cmap) < 0){
werrstr("loadrle: r=%R i->r=%R: %r", r, i->r);
free(buf);
return -1;
--- a/mcs.c
+++ b/mcs.c
@@ -1,4 +1,3 @@
-/* T.122 MCS, T.124 Generic Conference Control, T.125 MCS protocol */
#include <u.h>
#include <libc.h>
#include <draw.h>
@@ -14,20 +13,6 @@
TagEnum = 10,
TagSeq = 16, /* also TagSeq OF */
- /* ASN.1 tag numbers for MCS types */
- Mci= 101, /* Connect Initial */
- Mcr= 102, /* Connect Response */
- Medr= 1, /* Erect Domain Request */
- Maur= 10, /* Attach User Request */
- Mauc= 11, /* Attach User Confirm */
- Mcjr= 14, /* Channel Join Request */
- Mcjc= 15, /* Channel Join Confirm */
- Msdr= 25, /* Send Data Request */
- Msdi= 26, /* Send Data Indication */
- Mdpu= 8, /* Disconnect Provider Ultimatum */
-
- Musrchanbase= 1001,
-
/* 2.2.1.3 Client MCS Connect Initial PDU with GCC Conference Create Request */
ClientCore= 0xC001,
ClientCluster= 0xC004,
@@ -39,12 +24,8 @@
/* 2.2.1.3.1 User Data Header (TS_UD_HEADER) */
SrvCore = 0x0C01,
-
};
-int mkgcccr(uchar*,int);
-int sizegcccr(void);
-
enum
{
Bits5 = 0x1F,
@@ -51,10 +32,6 @@
Bits7 = 0x7F,
};
-static uchar* gblen(uchar*,uchar*,int*);
-static uchar* gbtag(uchar*,uchar*,int*);
-static void pbshort(uchar*,int);
-
static uchar*
gbuint7(uchar *p, uchar* ep, int* pv)
{
@@ -80,7 +57,7 @@
return p;
}
-static uchar*
+uchar*
gbtag(uchar *p, uchar* ep, int* ptag)
{
if(p >= ep){
@@ -94,7 +71,7 @@
return p;
}
-static uchar*
+uchar*
gblen(uchar *p, uchar* ep, int* plen)
{
int c,v;
@@ -125,7 +102,7 @@
return p+c;
}
-static void
+void
pbshort(uchar* p, int v)
{
p[0]=2;
@@ -136,11 +113,11 @@
int
mcstype(uchar* p, uchar* ep)
{
- if(!isdatatpdu(p,ep)){
+ if(!istpdat(p,ep)){
werrstr("not an X.224 Data TPDU");
return -1;
}
- p = tpdupayload(p, ep);
+ p = tpdat(p, ep);
if(p == nil)
return -1;
if(p >= ep){
@@ -157,13 +134,13 @@
}
int
-mcschanid(uchar *p, uchar* ep)
+mcschan(uchar *p, uchar* ep)
{
if(mcstype(p,ep) != Msdi){
werrstr("not an MCS Send Data Indication: %r");
return -1;
}
- if((p = tpdupayload(p, ep)) == nil)
+ if((p = tpdat(p, ep)) == nil)
return -1;
if(p+5 > ep){
werrstr(Eshort);
@@ -173,13 +150,13 @@
}
uchar*
-mcspayload(uchar *p, uchar* ep)
+mcsdat(uchar *p, uchar* ep)
{
if(mcstype(p,ep) != Msdi){
werrstr("not an MCS Send Data Indication: %r");
return nil;
}
- if((p = tpdupayload(p, ep)) == nil)
+ if((p = tpdat(p, ep)) == nil)
return nil;
if(p+6 > ep){
@@ -197,23 +174,6 @@
return p;
}
-/* MCS Send Data Request */
-int
-mkmcssdr(uchar* p, int nb, int ndata, int chanid)
-{
- if(nb < 8){
- werrstr(Esmall);
- return -1;
- }
-
- p[0] = (Msdr<<2);
- PSHORTB(p+1, rd.mcsuid);
- PSHORTB(p+3, chanid);
- p[5] = 0x70;
- PSHORTB(p+6, ndata|0x8000);
- return 8;
-}
-
/* 2.2.1.3 Client MCS Connect Initial PDU with GCC Conference Create Request */
int
mkmcsci(uchar* buf, int nbuf, int ndata)
@@ -296,40 +256,52 @@
/* GCC Conference Create Request [T.124 section 8.7] in ASN.1 PER [X.691] */
int
-sizegcccr(void)
+sizegccr(Msg* m)
{
- int size;
- size = 9+14+216+12+12 + 8+12*nvc;
+ int size, nv;
+
+ nv = m->nvc;
+ size = 9+14+216+12+12 + 8+12*nv;
return size; // should agree with the below
}
+
+static uchar t124IdentifierKeyOid[7] = {0, 5, 0, 20, 124, 0, 1};
+
int
-mkgcccr(uchar* buf, int nb)
+putgccr(uchar* buf, uint nb, Msg* m)
{
int i;
uchar *p, *ep;
long gccsize, earlyCapabilityFlags;
+ int ver, depth, width, height, sproto, wantconsole;
+ char* sysname;
+ Vchan *v;
+ int nv;
p = buf;
ep = buf+nb;
- gccsize = sizegcccr()-9;
+ gccsize = sizegccr(m)-9;
if(p+gccsize+9 > ep){
werrstr(Eshort);
return -1;
}
+ ver = m->ver;
+ depth = m->depth;
+ width = m->xsz;
+ height = m->ysz;
+ sysname = m->sysname;
+ sproto = m->sproto;
+ wantconsole = m->wantconsole;
+ v = m->vctab;
+ nv = m->nvc;
+
earlyCapabilityFlags = CanErrinfo;
- if(rd.depth == 32)
+ if(depth == 32)
earlyCapabilityFlags |= Want32bpp;
- // t124IdentifierKey: 0.0.20.124.0.1
- p[0] = 0;
- p[1] = 5;
- p[2] = 0;
- p[3] = 20;
- p[4] = 124;
- p[5] = 0;
- p[6] = 1;
+ memcpy(p, t124IdentifierKeyOid, 7);
// connectPDU as a PER octet string
PSHORTB(p+7, (gccsize | 0x8000)); // connectPDU length
@@ -336,9 +308,9 @@
PSHORTB(p+9, 8); // ConferenceCreateRequest
PSHORTB(p+11, 16);
p[13] = 0;
- PSHORT(p+14, 0xC001); // userData key: h221NonStandard. Yes, in LE.
+ PSHORT(p+14, 0xC001); // userData key: h221NonStandard
p[16] = 0;
- memcpy(p+17, "Duca", 4); // H.221 nonstandard key (as mandated in 3.2.5.3.3)
+ memcpy(p+17, "Duca", 4); // H.221 nonstandard key (3.2.5.3.3)
PSHORTB(p+21, ((gccsize-14) | 0x8000)); // userData length
p += 23;
@@ -345,14 +317,15 @@
// 2.2.1.3.2 Client Core Data
PSHORT(p+0, ClientCore);
PSHORT(p+2, 216); // length of the data block
- PLONG(p+4, 0x00080004); // rdpVersion: RDP5=0x00080004
- PSHORT(p+8, rd.dim.x); // desktopWidth ≤ 4096
- PSHORT(p+10, rd.dim.y); // desktopHeight ≤ 2048
+ PLONG(p+4, ver); // rdpVersion: RDP5=0x00080004
+ PSHORT(p+8, width); // desktopWidth ≤ 4096
+ PSHORT(p+10, height); // desktopHeight ≤ 2048
PSHORT(p+12, 0xCA01); // colorDepth=8bpp, ignored
PSHORT(p+14, 0xAA03); // SASSequence
PLONG(p+16, 0x409); // keyboardLayout=us
PLONG(p+20, 2600); // clientBuild
- toutf16(p+24, 32, rd.local, strlen(rd.local)); // clientName[32]
+ memset(p+24, 32, 0); // clientName[32]
+ toutf16(p+24, 32, sysname, strlen(sysname));
PSHORT(p+54, 0); // zero-terminateclientName
PLONG(p+56, 4); // keyboardType: 4="IBM enhanced (101-key or 102-key)"
PLONG(p+60, 0); // keyboardSubType
@@ -361,13 +334,13 @@
PSHORT(p+132, 0xCA01); // postBeta2ColorDepth=8bpp, ignored
PSHORT(p+134, 1); // clientProductId
PLONG(p+136, 0); // serialNumber
- PSHORT(p+140, MIN(rd.depth, 24)); // highColorDepth: 4, 8, 15, 16, 24 bpp.
+ PSHORT(p+140, MIN(depth, 24)); // highColorDepth: 4, 8, 15, 16, 24 bpp.
PSHORT(p+142, 1+2+4+8); // supportedColorDepths: 1=24, 2=16, 4=15, 8=32 bpp
PSHORT(p+144, earlyCapabilityFlags); // earlyCapabilityFlags
memset(p+146, 64, 0); // clientDigProductId[64]
p[210] = 7; // connectionType: 7=autodetect
p[211] = 0; // pad1octet
- PLONG(p+212, rd.sproto); // serverSelectedProtocol
+ PLONG(p+212, sproto); // serverSelectedProtocol
p += 216;
// 2.2.1.3.3 Client Security Data
@@ -380,7 +353,7 @@
// 2.2.1.3.5 Client Cluster Data *optional*
PSHORT(p+0, ClientCluster);
PSHORT(p+2, 12); // length of the data block
- PLONG(p+4, (rd.wantconsole? 11 : 9)); // Flags
+ PLONG(p+4, (wantconsole? 11 : 9)); // Flags
PLONG(p+8, 0); // RedirectedSessionID
p += 12;
@@ -387,155 +360,28 @@
// 2.2.1.3.4 Client Network Data *optional*
// type[2] len[2] nchan[4] nchan*(name[8] options[4])
PSHORT(p+0, ClientNet);
- PSHORT(p+2, 8+12*nvc);
- PLONG(p+4, nvc);
- for(i=0; i<nvc; i++){
- memcpy(p+8+12*i+0, vctab[i].name, 8);
- PLONGB(p+8+12*i+8, vctab[i].flags);
+ PSHORT(p+2, 8+12*nv);
+ PLONG(p+4, nv);
+ for(i=0; i<nv; i++){
+ memcpy(p+8+12*i+0, v[i].name, 8);
+ PLONGB(p+8+12*i+8, v[i].flags);
}
- p += 8+12*nvc;
+ p += 8+12*nv;
return p-buf;
}
-void
-erectdom(int fd)
-{
- uchar buf[20], *p;
- int len, nb;
-
- p = buf;
- nb = sizeof(buf);
- len = mktpdat(buf, nb, 5);
- if(len < 0)
- sysfatal("mktpdat: %r");
- p += TPDATAFIXLEN;
-
- p[0] = (Medr<<2);
- PSHORTB(p+1, 1);
- PSHORTB(p+3, 1);
- if(writen(fd, buf, len) != len)
- sysfatal("Erect Domain: write: %r");
-}
-
int
-attachuser(int fd)
+getmcr(Msg* m, uchar* b, uint nb)
{
- int len, tag, r, nb;
- uchar buf[20], *p, *ep;
+ int len, tag, r, utype, ulen;
+ uchar *p, *ep;
- nb = sizeof(buf);
- len = mktpdat(buf, nb, 1);
- if(len < 0)
- sysfatal("mktpdat: %r");
- buf[TPDATAFIXLEN] = (Maur<<2);
- if(writen(fd, buf, len) != len)
- sysfatal("Attach User: write: %r");
+ p = b;
+ ep = b+nb;
- len = readpdu(fd, buf, nb);
- if(len <= 0)
- sysfatal("readpdu: %r");
- p = buf;
- ep = buf+len;
- if(!isdatatpdu(p,ep))
- sysfatal("MCS: expected Data TPDU\n");
- p = tpdupayload(p, ep);
- if(p+2 > ep)
- sysfatal(Eshort);
+ m->type = Mconnected;
- tag = p[0]>>2;
- r = p[1];
- if(tag != Mauc)
- sysfatal("expected tag %d (Mauc), got %d", Mauc, tag);
- if(r != 0)
- sysfatal("Mauc error result: %d", r);
- if((p[0])&2){
- if(p+4 > ep)
- sysfatal(Eshort);
- rd.mcsuid = GSHORTB(p+2);
- rd.userchan = rd.mcsuid+Musrchanbase;
- }
- return r;
-}
-
-int
-joinchannel(int fd, int chanid)
-{
- uchar buf[32], *p, *ep;
- int tag, len, r, nb;
-
- p = buf;
- nb = sizeof(buf);
- len = mktpdat(buf, nb, 5);
- if(len < 0)
- sysfatal("mktpdat: %r");
- p += TPDATAFIXLEN;
- p[0] = (Mcjr << 2);
- PSHORTB(p+1, rd.mcsuid);
- PSHORTB(p+3, chanid);
- if(writen(fd, buf, len) != len)
- sysfatal("Channel Join: write: %r");
-
- len = readpdu(fd, buf, nb);
- if(len <= 0)
- sysfatal("readpdu: %r");
- p = buf;
- ep = buf+len;
- if(!isdatatpdu(p,ep))
- sysfatal("MCS: expected Data TPDU\n");
- p = tpdupayload(p, ep);
- if(p+2 > ep)
- sysfatal(Eshort);
-
- tag = p[0]>>2;
- r = p[1];
- if(tag != Mcjc)
- sysfatal("expected tag %d (Mcjc), got %d", Mcjc, tag);
- if(r != 0)
- sysfatal("Mcjc error result: %d", r);
-
- return r;
-
-}
-
-int
-mcsconnect(int fd)
-{
- uchar buf[MAXTPDU], *p, *ep;
- int n, ndata, nb, len, tag, r, ver, utype, ulen;
-
- /* 2.2.1.3 Client MCS Connect Initial PDU with GCC Conference Create Request */
- nb = sizeof(buf);
- ndata = sizegcccr();
- len = mktpdat(buf, nb, ndata+MCSCIFIXLEN);
- if(len < 0)
- sysfatal("mktpdat: %r");
- p = buf+TPDATAFIXLEN;
- ep = buf+nb;
- n = mkmcsci(p, ep-p, ndata);
- if(n != ndata+MCSCIFIXLEN)
- sysfatal("mkmcsci: %r");
- n = mkgcccr(p+MCSCIFIXLEN, ndata);
- if(n != ndata)
- sysfatal("mkgcccr: %r");
- if(writen(fd, buf, len) != len)
- sysfatal("TPDUDT: write: %r");
-
- /* 2.2.1.4 Server MCS Connect Response PDU with GCC Conference Create Response */
- len = readpdu(fd, buf, nb);
- if(len <= 0){
- werrstr("read MCS Connect Response PDU: %r");
- return -1;
- }
- p = buf;
- ep = buf+len;
-
- if(!isdatatpdu(p,ep)){
- werrstr("MCS: expected Data TPDU\n");
- return -1;
- }
- p = tpdupayload(p, ep);
-
/* at MCS Connect-Response ASN.1 BER-encoded structure */
if((p = gbtag(p, ep, &tag)) == nil || tag != Mcr || (p = gblen(p, ep, &len)) == nil)
return -1;
@@ -580,12 +426,29 @@
ulen = GSHORT(p+2);
switch(utype){
case SrvCore: /* 2.2.1.4.2 Server Core Data */
- ver = GLONG(p+4);
- assert(ver >= 0x00080004);
+ m->ver = GLONG(p+4);
break;
+ /* BUG: exract channel IDs from SrvNet */
}
p += ulen;
}
+ return p-b;
+}
- return r;
+
+/* MCS Send Data Request */
+int
+putmsdr(uchar* p, int nb, int ndata, int chanid, int mcsuid)
+{
+ if(nb < 8){
+ werrstr(Esmall);
+ return -1;
+ }
+
+ p[0] = (Msdr<<2);
+ PSHORTB(p+1, mcsuid);
+ PSHORTB(p+3, chanid);
+ p[5] = 0x70;
+ PSHORTB(p+6, ndata|0x8000);
+ return 8;
}
--- a/mkfile
+++ b/mkfile
@@ -4,7 +4,6 @@
BIN=/$objtype/bin
HFILES=fns.h dat.h
-CLEANFILES= x509.c
OFILES=\
cap.$O\
eclip.$O\
@@ -17,7 +16,10 @@
mouse.$O\
mpas.$O\
mppc.$O\
+ msg.$O\
rd.$O\
+ rpc.$O\
+ tls.$O\
utf16.$O\
vchan.$O\
wsys.$O\
@@ -24,19 +26,5 @@
x224.$O\
</sys/src/cmd/mkone
-
-x509.c: /sys/src/libsec/port/x509.c
- sed '
- /^ ALG_sha1WithRSAEncryption,/a\
- ALG_sha256WithRSAEncryption,\
- ALG_shaWithRSASignatureOiw,
- /^static Ints7 oid_sha1WithRSAEncryption =/a\
- static Ints7 oid_sha256WithRSAEncryption ={7, 1, 2, 840, 113549, 1, 1, 11 };\
- static Ints7 oid_shaWithRSASignatureOiw ={6, 1, 3, 14, 3, 2, 15 };
- /^ \(Ints\*\)\&oid_sha1WithRSAEncryption,/a\
- (Ints*)&oid_sha256WithRSAEncryption,\
- (Ints*)&oid_shaWithRSASignatureOiw,
- /^static DigestFun digestalg/ s/sha1,/sha1, sha2_256, sha1,/
- ' $prereq > $target
$TARG: mkfile
--- a/mouse.c
+++ b/mouse.c
@@ -6,68 +6,63 @@
#include "fns.h"
enum {
- MOUSE_FLAG_MOVE = 0x0800,
- MOUSE_FLAG_BUTTON1 = 0x1000,
- MOUSE_FLAG_BUTTON2 = 0x2000,
- MOUSE_FLAG_BUTTON3 = 0x4000,
- MOUSE_FLAG_BUTTON4 = 0x0280,
- MOUSE_FLAG_BUTTON5 = 0x0380,
- MOUSE_FLAG_DOWN = 0x8000,
+ MouseMove= 0x0800,
+ MouseB1= 0x1000,
+ MouseB2= 0x2000,
+ MouseB3= 0x4000,
+ MouseB4= 0x0280,
+ MouseB5= 0x0380,
+ MouseBdown= 0x8000,
};
static int mfd = -1;
static void
-sendmouse(Mouse m, int flags)
+sendmouse(Rdp* c, Mouse m, int flags)
{
- passinput(m.msec, InputMouse, flags, m.xy.x, m.xy.y);
+ passinput(c, m.msec, InputMouse, flags, m.xy.x, m.xy.y);
}
static void
-mouseevent(Mouse m)
+mouseevent(Rdp* c, Mouse m)
{
- ushort flags;
- int chg;
static Mouse o;
+ int down;
+ int chg;
+ m.xy = subpt(m.xy, screen->r.min);
switch(m.buttons){
case 8:
- sendmouse(m, MOUSE_FLAG_BUTTON4|MOUSE_FLAG_DOWN);
- sendmouse(m, MOUSE_FLAG_BUTTON4);
+ sendmouse(c, m, MouseB4|MouseBdown);
+ sendmouse(c, m, MouseB4);
return;
case 16:
- sendmouse(m, MOUSE_FLAG_BUTTON5|MOUSE_FLAG_DOWN);
- sendmouse(m, MOUSE_FLAG_BUTTON5);
+ sendmouse(c, m, MouseB5|MouseBdown);
+ sendmouse(c, m, MouseB5);
return;
}
if(!eqpt(m.xy, o.xy))
- sendmouse(m, MOUSE_FLAG_MOVE);
+ sendmouse(c, m, MouseMove);
chg = m.buttons ^ o.buttons;
if(chg&1){
- flags = MOUSE_FLAG_BUTTON1;
- if(m.buttons&1)
- flags |= MOUSE_FLAG_DOWN;
- sendmouse(m, flags);
+ down = (m.buttons&1)? MouseBdown : 0;
+ sendmouse(c, m, MouseB1|down);
}
if(chg&2){
- flags = MOUSE_FLAG_BUTTON3;
- if(m.buttons&2)
- flags |= MOUSE_FLAG_DOWN;
- sendmouse(m, flags);
+ down = (m.buttons&2)? MouseBdown : 0;
+ sendmouse(c, m, MouseB3|down);
}
if(chg&4){
- flags = MOUSE_FLAG_BUTTON2;
- if(m.buttons&4)
- flags |= MOUSE_FLAG_DOWN;
- sendmouse(m, flags);
+ down = (m.buttons&4)? MouseBdown : 0;
+ sendmouse(c, m, MouseB2|down);
}
o = m;
}
void
-readdevmouse(void)
+readdevmouse(Rdp* c)
{
Mouse m;
char ev[1+4*12];
@@ -79,14 +74,13 @@
if(read(mfd, ev, sizeof ev) != sizeof ev)
sysfatal("mouse eof");
if(*ev == 'm'){
- m.xy.x = atoi(ev+1);
- m.xy.y = atoi(ev+1+12);
- m.buttons = atoi(ev+1+2*12) & 0x1F;
- m.msec = atoi(ev+1+3*12);
- m.xy = subpt(m.xy, screen->r.min);
- mouseevent(m);
+ m.xy.x = atoi(ev+1+0*12);
+ m.xy.y = atoi(ev+1+1*12);
+ m.buttons = atoi(ev+1+2*12) & 0x1F;
+ m.msec = atoi(ev+1+3*12);
+ mouseevent(c, m);
}else
- eresized(1);
+ eresized(c, 1);
}
}
--- a/mpas.c
+++ b/mpas.c
@@ -1,673 +1,470 @@
-/*
- * Subset of: T.128 Multipoint application sharing
- *
- * 2.2.8.1.1.1.1 Share Control Header (TS_SHARECONTROLHEADER)
- * http://msdn.microsoft.com/en-us/library/cc240576.aspx
- *
- * totalLen[2] pduType[2] PDUSource[2]
- *
- * 2.2.9.1.1.3 says there may be many of these.
- */
+/* Based on: T.128 Multipoint application sharing */
#include <u.h>
#include <libc.h>
#include <draw.h>
#include "dat.h"
#include "fns.h"
-#define DBG if(0)
-//#define DBG
-
-uchar cmap[256];
-
static const char srcDesc[] = "Plan 9"; /* sourceDescriptor (T.128 section 8.4.1) */
-static void scanfastpath(uchar*,uchar*);
-static void scancursorpdu(uchar*, uchar*);
-static void scangraphpdu(uchar*,uchar*);
-static void scanimgupdate(uchar*,uchar*);
-static void scanpalette(uchar*,uchar*);
-static void scansrvcapset(uchar*,uchar*);
-static void sendclientinfo(void);
-static void confirmactive(void);
-static uchar* putsdh(uchar*,uchar*,int,int);
-static void assync(void);
-static void asctl(int);
-static void asfontls(void);
-
enum
{
Bits4= 0x0F,
- SECHSIZE= 4,
- SCHSIZE= 6,
- SCDSIZE= SCHSIZE+4+4+2*2,
-};
-enum /* 2.2.8.1.1.1.1 Share Control Header (TS_SHARECONTROLHEADER) */
-{
- PDUTYPE_DEMANDACTIVEPDU = 1, /* Demand Active PDU (section 2.2.1.13.1) */
- PDUTYPE_CONFIRMACTIVEPDU = 3, /* Confirm Active PDU (section 2.2.1.13.2) */
- PDUTYPE_DEACTIVATEALLPDU = 6, /* Deactivate All PDU (section 2.2.3.1) */
- PDUTYPE_DATAPDU = 7, /* Data PDU */
- PDUTYPE_SERVER_REDIR_PKT = 10, /* Redirection PDU (section 2.2.13.3.1). */
-};
-
-enum /* 2.2.8.1.1.1.2 Share Data Header (TS_SHAREDATAHEADER) */
-{
- PDUTYPE2_UPDATE= 2,
- PDUTYPE2_CONTROL= 20,
- PDUTYPE2_POINTER= 27,
- PDUTYPE2_INPUT= 28,
- PDUTYPE2_SYNCHRONIZE= 31,
- PDUTYPE2_REFRESH_RECT= 33,
- PDUTYPE2_SUPPRESS_OUTPUT= 35,
- PDUTYPE2_FONTLIST= 39,
- PDUTYPE2_FONTMAP= 40,
- PDUTYPE2_SET_ERROR_INFO_PDU= 47,
-};
-
-enum /* 2.2.9.1.1.4 Server Pointer Update PDU (TS_POINTER_PDU) */
-{
- TS_PTRMSGTYPE_SYSTEM= 1,
- TS_PTRMSGTYPE_POSITION= 3,
- TS_PTRMSGTYPE_COLOR= 6,
- TS_PTRMSGTYPE_CACHED= 7,
- TS_PTRMSGTYPE_POINTER= 8,
-};
-
-enum /* 2.2.9.1.1.3.1.2.2 Bitmap Data */
-{
+ /* 2.2.9.1.1.3.1.2.2 Bitmap Data */
Bcompress= 1,
Pcompress= 0x20,
-};
-enum /* 2.2.1.15.1 Control PDU Data */
-{
- CTRLACTION_REQUEST_CONTROL= 1,
- CTRLACTION_GRANTED_CONTROL= 2,
- CTRLACTION_DETACH= 3,
- CTRLACTION_COOPERATE= 4,
-};
+ /* 2.2.8.1.1.1.1 Share Control Header */
+ PDUactivate = 1, /* Demand Active PDU (section 2.2.1.13.1) */
+ PDUactivated = 3, /* Confirm Active PDU (section 2.2.1.13.2) */
+ PDUdeactivate = 6, /* Deactivate All PDU (section 2.2.3.1) */
+ PDUdata = 7, /* Data PDU */
-enum /* 2.2.1.11.1.1 Info Packet (TS_INFO_PACKET) */
-{
- INFO_MOUSE= 0x1,
- INFO_DISABLECTRLALTDEL= 0x2,
- INFO_AUTOLOGON= 0x8,
- INFO_UNICODE= 0x10,
- INFO_MAXIMIZESHELL= 0x20,
- INFO_COMPRESSION= 0x80,
- CompressionTypeMask= 0x1E00,
- PACKET_COMPR_TYPE_8K= 0<<9, // RDP 4.0 bulk compression ≡ MPPC
- PACKET_COMPR_TYPE_64K= 1<<9, // RDP 5.0 bulk compression (3.1.8.4.2)
- PACKET_COMPR_TYPE_RDP6= 2<<9, // RDP 6.0 bulk compression
- PACKET_COMPR_TYPE_RDP61= 3<<9, // RDP 6.1 bulk compression
- INFO_ENABLEWINDOWSKEY= 0x100,
- INFO_REMOTECONSOLEAUDIO= 0x2000,
- INFO_FORCE_ENCRYPTED_CS_PDU= 0x4000,
- INFO_RAIL= 0x8000,
- INFO_LOGONERRORS= 0x10000,
- INFO_MOUSE_HAS_WHEEL= 0x20000,
- INFO_NOAUDIOPLAYBACK= 0x80000,
- INFO_VIDEO_DISABLE= 0x400000,
+ /* 2.2.9.1.1.4 Server Pointer Update PDU (TS_POINTER_PDU) */
+ PDUcursorwarp= 3,
- PERF_DISABLE_WALLPAPER= 1<<0,
- PERF_DISABLE_FULLWINDOWDRAG= 1<<1,
- PERF_DISABLE_MENUANIMATIONS= 1<<2,
- PERF_DISABLE_THEMING= 1<<3,
- PERF_DISABLE_CURSOR_SHADOW= 1<<5,
- PERF_DISABLE_CURSORSETTINGS= 1<<6,
- PERF_ENABLE_FONT_SMOOTHING= 1<<7,
-};
+ /* 2.2.1.11.1.1 Info Packet (TS_INFO_PACKET) */
+ InfMouse= 1<<0,
+ InfNoctlaltdel= 1<<1,
+ InfAutologon= 1<<3,
+ InfUnicode= 1<<4,
+ InfMaxshell= 1<<5,
+ InfCompress= 1<<7,
+ InfWinkey= 1<<8,
+ Compress64k= 1<<9, // RDP 5.0 bulk compression (3.1.8.4.2)
-enum
-{
- UPDATETYPE_ORDERS = 0, /* [MS-RDPEGDI] section 2.2.2.2 */
- UPDATETYPE_BITMAP = 1, /* section 2.2.9.1.1.3.1.2 */
- UPDATETYPE_PALETTE = 2, /* section 2.2.9.1.1.3.1.1 */
- UPDATETYPE_SYNCHRONIZE = 3, /* section 2.2.9.1.1.3.1.3 */
-};
+ PerfNoDrag= 1<<1,
+ PerfNoAnim= 1<<2,
+ PerfNoTheming= 1<<3,
+ PerfNoCursorset= 1<<6,
+ PerfFontAA= 1<<7,
+
+ /* 2.2.9.1.1.3.1 Slow-Path Graphics Update (TS_GRAPHICS_UPDATE) */
+ UpdOrders= 0,
+ UpdBitmap= 1, /* section 2.2.9.1.1.3.1.2 */
+ UpdCmap= 2, /* section 2.2.9.1.1.3.1.1 */
-enum /* 2.2.9.1.2.1 Fast-Path Update (TS_FP_UPDATE) */
-{
- FASTPATH_UPDATETYPE_ORDERS = 0, /* [MS-RDPEGDI] section 2.2.2.2 */
- FASTPATH_UPDATETYPE_BITMAP = 1,
- FASTPATH_UPDATETYPE_PALETTE = 2,
- FASTPATH_UPDATETYPE_SYNCHRONIZE = 3,
- FASTPATH_UPDATETYPE_SURFCMDS = 4,
- FASTPATH_UPDATETYPE_PTR_NULL = 5,
- FASTPATH_UPDATETYPE_PTR_DEFAULT = 6,
- FASTPATH_UPDATETYPE_PTR_POSITION = 8,
- FASTPATH_UPDATETYPE_COLOR = 9,
- FASTPATH_UPDATETYPE_CACHED = 10,
- FASTPATH_UPDATETYPE_POINTER = 11,
+ /* 2.2.9.1.2.1 Fast-Path Update (TS_FP_UPDATE) */
+ FUpdOrders= 0,
+ FUpdBitmap= 1,
+ FUpdCmap= 2,
+ FUpdWarp= 8,
+ /* 2.2.7.1.1 General Capability Set (TS_GENERAL_CAPABILITYSET) */
+ NoBitcomphdr = 0x0400,
};
+
+/* 2.2.9.1.2.1 Fast-Path Update (TS_FP_UPDATE)
+ *
+ * updateHeader[1] compressionFlags[1]? size[2] updateData[*]
+ */
int
-rdphandshake(int)
+getshareF(Share* as, uchar* a, uint nbytes)
{
- int i;
+ int hd, nb, cflags, ulen;
+ uchar *p, *ep, *q;
- if(mcsconnect(rd.fd) < 0)
+ as->type = 0;
+ if(nbytes < 3){
+ werrstr(Eshort);
return -1;
- erectdom(rd.fd);
- if(attachuser(rd.fd) < 0)
- return -1;
- if(joinchannel(rd.fd, rd.userchan) < 0)
- return -1;
- if(joinchannel(rd.fd, GLOBALCHAN) < 0)
- return -1;
- for(i = 0; i < nvc; i++)
- if(joinchannel(rd.fd, vctab[i].mcsid) < 0)
- return -1;
+ }
- sendclientinfo();
- return rd.fd;
-}
+ p = a;
+ ep = a+nbytes;
-void
-readnet(int fd)
-{
- int chanid, len, flags;
- uchar *p, *ep, buf[MAXTPDU];
-
- for(;;){
- len = readpdu(fd, buf, sizeof(buf));
- if(len <= 0){
- if(rd.active && !rd.hupreason)
- fprint(2, "readpdu: %r\n");
- return;
+ hd = *p++;
+ if(hd&(1<<7))
+ cflags = *p++;
+ else
+ cflags = 0;
+ if(p+2 > ep){
+ werrstr(Eshort);
+ return -1;
+ }
+ nb = GSHORT(p);
+ p += 2;
+ q = p+nb;
+ if(cflags&Pcompress){
+ if(p+nb > ep){
+ werrstr("bad length %d in Fast-Path PDU header", nb);
+ return -1;
}
- p = buf;
- ep = buf+len;
-
- if(istpkt(p,ep) == 0){
- scanfastpath(p, ep);
- continue;
+ if((p = uncomp(p, nb, cflags, &ulen)) == nil){
+ werrstr("fast-path packet de-compression failed: %r cflags=%#x", cflags);
+ return -1;
}
- if(ismcshangup(p,ep)){
- werrstr("Disconnect Provider Ultimatum");
- return;
- }
+ ep = p+ulen;
+ }
- chanid = mcschanid(p,ep);
- if(chanid < 0)
- sysfatal("mcschanid: %r");
-
- p = mcspayload(p, ep);
-
- flags = GSHORT(p);
- if(!rd.licensed && flags&Slicensepk){
- /*
- * 2.2.8.1.1.2.1 Basic (TS_SECURITY_HEADER)
- * http://msdn.microsoft.com/en-us/library/cc240579.aspx
- */
- p += SECHSIZE;
- if(flags&Slicensepk){
- scanlicensepdu(p, ep);
- continue;
- }
- if(flags&Scrypt)
- sysfatal("legacy encryption of a Slow-Path PDU");
+ switch(hd&Bits4){
+ case FUpdOrders:
+ if(p+2>ep){
+ werrstr(Eshort);
+ return -1;
}
-
- if(chanid != GLOBALCHAN){
- scanvcpdu(p, ep, chanid);
- continue;
+ as->type = ShUorders;
+ as->nord = GSHORT(p);
+ as->data = p+2;
+ as->ndata = ep-(p+2);
+ break;
+ case FUpdBitmap:
+ if(p+4>ep){
+ werrstr(Eshort);
+ return -1;
}
-
- if(isflowpdu(p,ep))
- continue;
-
- scanaspdu(p,ep);
+ as->type = ShUimg;
+ as->nrect = GSHORT(p+2);
+ as->data = p+4;
+ as->ndata = ep-(p+4);
+ break;
+ case FUpdCmap:
+ as->type = ShUcmap;
+ as->data = p;
+ as->ndata = ep-p;
+ break;
+ case FUpdWarp:
+ if(p+4>ep){
+ werrstr(Eshort);
+ return -1;
+ }
+ as->type = ShUwarp;
+ as->x = GSHORT(p+0);
+ as->y = GSHORT(p+2);
+ break;
}
+ return q-a;
}
-/* T.128 FlowPDU */
+/*
+ * T.128 ASPDU
+ *
+ * 2.2.8.1.1.1.1 Share Control Header
+ * https://msdn.microsoft.com/en-us/library/cc240576.aspx
+ *
+ * totalLength[2] pduType[2] pduSource[2]
+ */
int
-isflowpdu(uchar* p, uchar* ep)
+getshareT(Share* as, uchar* p, uint nb)
{
- int marker;
+ int len, nsrc, type;
+ int pduType2, ctype, mtype, uptype, clen, ulen, ulenr;
+ uchar *ep;
- if(p+2 > ep){
+ as->type = 0;
+ if(nb < 6){
werrstr(Eshort);
return -1;
}
- marker = GSHORT(p);
- return marker == 0x8000;
-}
+ len = GSHORT(p);
+ if(len < SCHSIZE || len > nb){
+ werrstr("bad length in Share Control PDU header");
+ return -1;
+ }
+ type = GSHORT(p+2)&Bits4;
+ as->source = GSHORT(p+4);
-/* 2.2.9.1.2 Server Fast-Path Update PDU
- * enabled with CanFastpath in General Capability Set
- */
-static void
-scanfastpath(uchar *p, uchar* ep)
-{
- int hd, nb, nord, cflags, ulen, x, y, enc;
- uchar *q, *eq;
-
- enc = p[0]&(1<<7);
- if(enc)
- sysfatal("legacy encryption in a Fast-Path PDU");
- if(p[1]&(1<<7))
- p += 3;
- else
- p += 2;
-
- eq = ep;
- while(p+3 < ep){
- /* updateHeader[1] compressionFlags[1]? size[2] updateData[*] */
- hd = *p++;
- if(hd&(1<<7))
- cflags = *p++;
- else
- cflags = 0;
- if(p+2 > ep)
- sysfatal(Eshort);
- nb = GSHORT(p);
- p += 2;
- q = p+nb;
-
- if(cflags&Pcompress){
- if(p+nb > ep)
- sysfatal(Eshort);
- if((p = uncomp(p, nb, cflags, &ulen)) == nil)
- sysfatal("fast-path packet de-compression failed: %r cflags=%#x", cflags);
- ep = p+ulen;
+ switch(type){
+ case PDUactivate:
+ /*
+ * 2.2.1.13.1 Server Demand Active PDU
+ * http://msdn.microsoft.com/en-us/library/cc240484.aspx
+ */
+ as->type = ShActivate;
+ if(len<14){
+ werrstr(Eshort);
+ return -1;
}
-
- switch(hd&Bits4){
- case FASTPATH_UPDATETYPE_ORDERS:
- nord = GSHORT(p);
- scanorders(p+2, ep, nord);
- break;
- case FASTPATH_UPDATETYPE_BITMAP:
- scanimgupdate(p, ep);
- break;
- case FASTPATH_UPDATETYPE_PALETTE:
- scanpalette(p, ep);
- break;
- case FASTPATH_UPDATETYPE_PTR_POSITION:
- x = GSHORT(p+0);
- y = GSHORT(p+2);
- warpmouse(x, y);
- break;
+ as->shareid = GLONG(p+6);
+ nsrc = GSHORT(p+10);
+ as->ndata = GSHORT(p+12);
+ if(len<14+nsrc+as->ndata){
+ werrstr(Eshort);
+ return -1;
}
-
- p = q;
- ep = eq;
- }
-
- lockdisplay(display);
- flushimage(display, 1);
- unlockdisplay(display);
-}
-
-/* T.128 ASPDU */
-void
-scanaspdu(uchar* p, uchar* ep)
-{
- int pdutype, len;
-
- while(p+SCHSIZE <= ep){
- len = GSHORT(p);
- if(len < SCHSIZE || p+len > ep)
- sysfatal("bad length in Share Control PDU header");
+ as->data = p+14+nsrc;
+ as->ncap = GSHORT(p+14+nsrc);
+ break;
+ case PDUdeactivate:
+ as->type = ShDeactivate;
+ break;
+ case PDUdata:
+ /*
+ * 2.2.8.1.1.1.2 Share Data Header (TS_SHAREDATAHEADER)
+ * http://msdn.microsoft.com/en-us/library/cc240577.aspx
+ *
+ * shareId[4] pad1[1] streamId[1] uncomprLen[2]
+ * pduType2[1] comprType[1] comprLen[2]
+ */
+ ep = p+nb;
- pdutype = GSHORT(p+2)&Bits4;
+ if(nb < 18){
+ werrstr("%s (%ud<18)", Eshort, nb);
+ return -1;
+ }
+
+ ulen = GSHORT(p+12);
+ pduType2 = p[14];
+ ctype = p[15];
+ clen = GSHORT(p+16) - SCDSIZE;
+ p += 18;
+
+ if(ctype&(1<<5)){
+ if(p+clen > ep){
+ werrstr(Eshort);
+ return -1;
+ }
+ if((p = uncomp(p, clen, ctype, &ulenr)) == nil){
+ werrstr("decompression failed: %r");
+ return -1;
+ }
+ if(ulen != ulenr+SCDSIZE){
+ werrstr("bad length after decompression");
+ return -1;
+ }
+ ep = p+ulenr;
+ }
- switch(pdutype){
- case PDUTYPE_DEMANDACTIVEPDU:
- activating(p+SCHSIZE, p+len);
- rd.active = 1;
+ /* BUG add more boundary checks */
+
+ switch (pduType2){
+ case ADsync:
+ as->type = ShSync;
break;
- case PDUTYPE_DATAPDU:
- scandatapdu(p+SCHSIZE, p+len);
+ case ADctl:
+ as->type = ShCtl;
break;
- case PDUTYPE_DEACTIVATEALLPDU:
- rd.active = 0;
+ case ADfontmap: /* denotes completion of the connection sequence */
+ as->type = ShFmap;
break;
+ case ADerrx:
+ /* 2.2.5.1.1 Set Error Info PDU Data (TS_SET_ERROR_INFO_PDU) */
+ as->type = ShEinfo;
+ as->err = GLONG(p);
+ break;
+ case ADdraw:
+ /* 2.2.9.1.1.3.1 Slow-Path Graphics Update (TS_GRAPHICS_UPDATE) */
+ /* not when Fast-Path is in use */
+ if(p+2 > ep){
+ werrstr("ADdraw: %s", Eshort);
+ return -1;
+ }
+ uptype = GSHORT(p);
+ switch(uptype){
+ case UpdOrders:
+ if(p+8 > ep){
+ werrstr("ShUorders: %s", Eshort);
+ return -1;
+ }
+ as->type = ShUorders;
+ as->nord = GSHORT(p+4);
+ as->data = p+8;
+ as->ndata = ep-(p+8);
+ break;
+ case UpdBitmap:
+ if(p+4 > ep){
+ werrstr("ShUimg: %s", Eshort);
+ return -1;
+ }
+ as->type = ShUimg;
+ as->nrect = GSHORT(p+2);
+ as->data = p+4;
+ as->ndata = ep-(p+4);
+ break;
+ case UpdCmap:
+ as->type = ShUcmap;
+ as->data = p;
+ as->ndata = ep-p;
+ break;
+ }
+ break;
+ case ADcursor:
+ /* 2.2.9.1.1.4 Server Pointer Update PDU (TS_POINTER_PDU) */
+ if(p+2 > ep){
+ werrstr(Eshort);
+ return -1;
+ }
+ mtype = GSHORT(p);
+ if(mtype == PDUcursorwarp){
+ if(p+8 > ep){
+ werrstr(Eshort);
+ return -1;
+ }
+ as->type = ShUwarp;
+ as->x = GSHORT(p+4);
+ as->y = GSHORT(p+6);
+ break;
+ }
}
- p += len;
- }
-}
-
-/*
- * 2.2.8.1.1.1.2 Share Data Header (TS_SHAREDATAHEADER)
- * http://msdn.microsoft.com/en-us/library/cc240577.aspx
- *
- * shareId[4] pad1[1] streamId[1] uncomprLen[2]
- * pduType2[1] comprType[1] comprLen[2]
- */
-void
-scandatapdu(uchar *p, uchar* ep)
-{
- int pduType2, ctype, clen, ulen, ulenr;
-
- ulen = GSHORT(p+6);
- pduType2 = p[8];
- ctype = p[9];
- clen = GSHORT(p+10);
- p += 12;
-
- if(ctype&(1<<5)){
- clen -= SCDSIZE;
- if(p+clen > ep)
- sysfatal(Eshort);
- if((p = uncomp(p, clen, ctype, &ulenr)) == nil)
- sysfatal("decompression failed: %r");
- if(ulen != ulenr+SCDSIZE)
- sysfatal("bad length after decompression");
- ep = p+ulenr;
- }
-
- switch (pduType2){
- case PDUTYPE2_SYNCHRONIZE:
- case PDUTYPE2_CONTROL:
- case PDUTYPE2_FONTMAP: /* denotes completion of the connection sequence */
break;
- case PDUTYPE2_SET_ERROR_INFO_PDU:
- /* 2.2.5.1.1 Set Error Info PDU Data (TS_SET_ERROR_INFO_PDU) */
- rd.hupreason = GLONG(p);
- break;
- case PDUTYPE2_UPDATE:
- scangraphpdu(p, ep);
- break;
- case PDUTYPE2_POINTER:
- scancursorpdu(p, ep);
- break;
}
+ return len;
}
-/* 2.2.9.1.1.3.1 Slow-Path Graphics Update (TS_GRAPHICS_UPDATE) */
-static void
-scangraphpdu(uchar *p, uchar *ep)
+/* 2.2.9.1.1.3.1.2.2 Bitmap Data (TS_BITMAP_DATA) */
+int
+getimgupd(Imgupd* iu, uchar* a, uint nb)
{
- int uptype, nord;
+ uchar *p, *ep, *s;
+ int opt, len;
- if(p+2 > ep)
- sysfatal(Eshort);
-
- uptype = GSHORT(p);
- switch(uptype){
- case UPDATETYPE_ORDERS:
- if(p+8 > ep)
- sysfatal(Eshort);
- nord = GSHORT(p+4);
- scanorders(p+8, ep, nord);
- break;
- case UPDATETYPE_BITMAP:
- scanimgupdate(p, ep);
- break;
- case UPDATETYPE_PALETTE:
- scanpalette(p, ep);
- break;
+ p = a;
+ ep = a+nb;
+ if(nb < 18){
+ werrstr(Eshort);
+ return -1;
}
- lockdisplay(display);
- flushimage(display, 1);
- unlockdisplay(display);
-}
-
-/* 2.2.9.1.1.4 Server Pointer Update PDU (TS_POINTER_PDU) */
-static void
-scancursorpdu(uchar* p, uchar* ep)
-{
- int type, x, y;
-
- if(p+2 > ep)
- sysfatal(Eshort);
- type = GSHORT(p);
- switch(type){
- case TS_PTRMSGTYPE_POSITION:
- if(p+8 > ep)
- sysfatal(Eshort);
- x = GSHORT(p+4);
- y = GSHORT(p+6);
- warpmouse(x, y);
- break;
+ iu->x = GSHORT(p+0);
+ iu->y = GSHORT(p+2);
+ iu->xm = GSHORT(p+4);
+ iu->ym = GSHORT(p+6);
+ iu->xsz = GSHORT(p+8);
+ iu->ysz = GSHORT(p+10);
+ iu->depth = GSHORT(p+12);
+ opt = GSHORT(p+14);
+ len = GSHORT(p+16);
+ p += 18;
+ s = p+len;
+ if(s > ep){
+ werrstr(Eshort);
+ return -1;
}
+ iu->iscompr = (opt&Bcompress);
+ if(opt&Bcompress && !(opt&NoBitcomphdr))
+ p += 8;
+ iu->bytes = p;
+ iu->nbytes = s-p;
+ return s-a;
}
-/* 2.2.9.1.1.3.1.2.1 Bitmap Update Data (TS_UPDATE_BITMAP_DATA) */
-static void
-scanimgupdate(uchar* p, uchar* ep)
+/* T.128 FlowPDU */
+int
+isflowpdu(uchar* p, uchar* ep)
{
- uchar *s;
- int err, nr, len, depth, chan, opt;
- static Image* img;
- Rectangle r, rs, d;
+ int marker;
- if(p+4 > ep)
- sysfatal(Eshort);
- chan = rd.chan;
- rs = rectaddpt(Rpt(ZP, rd.dim), screen->r.min);
- nr = GSHORT(p+2);
- p += 4;
-
- lockdisplay(display);
-
- if(img==nil || !eqrect(img->r, rs)){
- if(img != nil)
- freeimage(img);
- img = allocimage(display, rs, chan, 0, DNofill);
- if(img == nil)
- sysfatal("%r");
- }
-
- for(; nr>0 && p+18<ep; nr--){
- /* 2.2.9.1.1.3.1.2.2 Bitmap Data (TS_BITMAP_DATA) */
- d.min.x = GSHORT(p+0);
- d.min.y = GSHORT(p+2);
- d.max.x = GSHORT(p+4) + 1;
- d.max.y = GSHORT(p+6) + 1;
- r.min = ZP;
- r.max.x = GSHORT(p+8);
- r.max.y = GSHORT(p+10);
- depth = GSHORT(p+12);
- opt = GSHORT(p+14);
- len = GSHORT(p+16);
- p += 18;
- s = p+len;
- if(s > ep)
- sysfatal(Eshort);
- if(depth != img->depth)
- sysfatal("bad image depth");
- r = rectaddpt(r, img->r.min);
-
- if(opt&Bcompress)
- if(!(opt&NoBitcomphdr))
- p += 8;
-
- err = (opt&Bcompress? loadrle : loadbmp)(img, r, p, s-p);
- if(err < 0)
- sysfatal("%r");
- draw(screen, rectaddpt(d, screen->r.min), img, nil, img->r.min);
- p = s;
- }
- unlockdisplay(display);
-}
-
-static void
-scanpalette(uchar* p, uchar* ep)
-{
- int i, n;
-
- n = GSHORT(p+4);
- p += 8;
- if(n > sizeof(cmap)){
- fprint(2, "scanpalette: palette too big");
- return;
- }
- if(p+3*n > ep)
- sysfatal(Eshort);
- for(i = 0; i<n; i++, p+=3)
- cmap[i] = rgb2cmap(p[0], p[1], p[2]);
-}
-
-static void
-scansrvcapset(uchar *p, uchar *ep)
-{
- int ncap, type, len;
-
- ncap = GSHORT(p);
- p += 4;
- for(; ncap>0 && p+4<ep; ncap--){
- type = GSHORT(p+0);
- len = GSHORT(p+2);
- if(p+len > ep)
- sysfatal("bad length in server's capability set");
- switch (type){
- case CapGeneral:
- scangencaps(p, p+len);
- break;
- case CapBitmap:
- scanbitcaps(p, p+len);
- break;
- }
- p += len;
- }
-}
-
-/*
- * 2.2.1.13.1 Server Demand Active PDU
- * http://msdn.microsoft.com/en-us/library/cc240484.aspx
- */
-void
-activating(uchar* p, uchar* ep)
-{
- int nsrc, ncaps;
-
- rd.shareid = GLONG(p);
- nsrc = GSHORT(p+4);
- ncaps = GSHORT(p+6);
- p += 8+nsrc;
- if(p+ncaps >= ep){
+ if(p+2 > ep){
werrstr(Eshort);
- return;
+ return -1;
}
- scansrvcapset(p, p+ncaps);
- confirmactive();
- // server accepts input since this point
- passinput(0, InputSync, 0, 0, 0);
-
- assync();
- asctl(CTRLACTION_COOPERATE);
- asctl(CTRLACTION_REQUEST_CONTROL);
- asfontls(); // unleashes the artist
+ marker = GSHORT(p);
+ return marker == 0x8000;
}
/* 2.2.1.13.2 Client Confirm Active PDU */
-static void
-confirmactive(void)
+int
+putconfirmactive(uchar* b, uint nb, Msg* m)
{
- int ncap, nsrc, capsize, calen, pdusize;
- uchar buf[512], *p, *q, *ep;
+ uchar *p, *q, *ep;
+ int n, nsrc, capsize, ndata, pdusize;
+ int userchan, shareid, originid;
+ Caps caps;
- ncap = 8;
+ assert(m->type == Mactivated);
+ userchan = m->mcsuid;
+ shareid = m->shareid;
+ originid = m->originid;
+
+ caps.depth = m->depth;
+ caps.xsz = m->xsz;
+ caps.ysz = m->ysz;
+
nsrc = sizeof(srcDesc);
- capsize = 0
- + GENCAPSIZE
- + BITCAPSIZE
- + ORDCAPSIZE
- + BCACAPSIZE
- + PTRCAPSIZE
- + INPCAPSIZE
- + SNDCAPSIZE
- + GLYCAPSIZE
- ;
- calen = 20+nsrc+capsize;
+ capsize = sizecaps(&caps);
+ ndata = 16+nsrc+capsize;
- p = prebuf(buf, sizeof(buf), calen, 0, 0);
+ p = txprep(b, nb, ndata, 0, userchan, 0);
if(p == nil)
sysfatal("buffer not prepared: %r");
- ep = p+calen;
- pdusize = ep-buf;
+ ep = p+ndata;
+ pdusize = ep-b;
q = p;
/* 2.2.8.1.1.1.1 Share Control Header */
/* totalLength[2] pduType[2] PDUSource[2] */
- PSHORT(p+0, calen);
- PSHORT(p+2, PDUTYPE_CONFIRMACTIVEPDU | (1<<4));
- PSHORT(p+4, rd.userchan);
+ PSHORT(p+0, ndata);
+ PSHORT(p+2, PDUactivated | (1<<4));
+ PSHORT(p+4, userchan);
/* shareId[4] originatorId[2] sdlen[2] caplen[2] srcdesc[sdlen] ncap[2] pad[2] */
- PLONG(p+6, rd.shareid);
- PSHORT(p+10, SRVCHAN);
+ PLONG(p+6, shareid);
+ PSHORT(p+10, originid);
PSHORT(p+12, nsrc);
- PSHORT(p+14, capsize+4);
+ PSHORT(p+14, capsize);
memcpy(p+16, srcDesc, nsrc);
- PSHORT(p+16+nsrc, ncap);
- PSHORT(p+18+nsrc, 0);
- p += nsrc+20;
- p = putgencaps(p, ep);
- p = putbitcaps(p, ep);
- p = putordcaps(p, ep);
- p = putbc2caps(p, ep);
- p = putptrcaps(p, ep);
- p = putinpcaps(p, ep);
- p = putsndcaps(p, ep);
- p = putglycaps(p, ep);
- assert(p-calen == q);
-
- writen(rd.fd, buf, pdusize);
+ p += nsrc+16;
+ if((n = putcaps(p, ep-p, &caps)) < 0)
+ sysfatal("putcaps: %r");
+ p += n;
+ assert(p-ndata == q);
+ return pdusize;
}
/* 2.2.1.11 Client Info PDU */
-static void
-sendclientinfo(void)
+int
+putclientinfo(uchar* b, uint nb, Msg* m)
{
- uchar a[1024], *p, *q;
- int ndata, secflags, usize;
+ uchar *p, *q;
+ int ndata, usize;
int opt, perfopt;
int ndom, nusr, npw, nsh, nwd;
uchar *wdom, *wusr, *wpw, *wsh, *wwd;
+ char *dom, *usr, *pw, *sh, *wd;
+ int dologin;
- ndom = strlen(rd.windom)+1;
- nusr = strlen(rd.user)+1;
- npw = strlen(rd.passwd)+1;
- nsh = strlen(rd.shell)+1;
- nwd = strlen(rd.rwd)+1;
+ assert(m->type == Dclientinfo);
+ dom = m->dom;
+ usr = m->user;
+ pw = m->pass;
+ sh = m->rshell;
+ wd = m->rwd;
+ dologin = m->dologin;
+
+ ndom = strlen(dom)+1;
+ nusr = strlen(usr)+1;
+ npw = strlen(pw)+1;
+ nsh = strlen(sh)+1;
+ nwd = strlen(wd)+1;
wdom = emalloc(4*ndom);
wusr = emalloc(4*nusr);
wpw = emalloc(4*npw);
wsh = emalloc(4*nsh);
wwd = emalloc(4*nwd);
- ndom = toutf16(wdom, 4*ndom, rd.windom, ndom);
- nusr = toutf16(wusr, 4*nusr, rd.user, nusr);
- npw = toutf16(wpw, 4*npw, rd.passwd, npw);
- nsh = toutf16(wsh, 4*nsh, rd.shell, nsh);
- nwd = toutf16(wwd, 4*nwd, rd.rwd, nwd);
+ ndom = toutf16(wdom, 4*ndom, dom, ndom);
+ nusr = toutf16(wusr, 4*nusr, usr, nusr);
+ npw = toutf16(wpw, 4*npw, pw, npw);
+ nsh = toutf16(wsh, 4*nsh, sh, nsh);
+ nwd = toutf16(wwd, 4*nwd, wd, nwd);
ndata = 18+ndom+nusr+npw+nsh+nwd+188;
opt = 0
- | INFO_MOUSE
- | INFO_UNICODE
- | INFO_DISABLECTRLALTDEL
- | INFO_MAXIMIZESHELL
- | INFO_ENABLEWINDOWSKEY
- | INFO_FORCE_ENCRYPTED_CS_PDU
- | INFO_COMPRESSION
- | PACKET_COMPR_TYPE_8K
- | PACKET_COMPR_TYPE_64K
- ;
+ | InfMouse
+ | InfUnicode
+ | InfNoctlaltdel
+ | InfMaxshell
+ | InfWinkey
+ | InfCompress
+ | Compress64k
+ ;
+ if(dologin)
+ opt |= InfAutologon;
perfopt = 0
- | PERF_DISABLE_FULLWINDOWDRAG
- | PERF_DISABLE_MENUANIMATIONS
- | PERF_DISABLE_CURSORSETTINGS
- | PERF_DISABLE_THEMING
- ;
- if(rd.autologon)
- opt |= INFO_AUTOLOGON;
+ | PerfNoDrag
+ | PerfNoAnim
+ | PerfNoCursorset
+ | PerfNoTheming
+ ;
- secflags = Sinfopk;
- p = prebuf(a, sizeof(a), ndata, 0, secflags);
+ p = txprep(b, nb, ndata, 0, m->mcsuid, Sinfopk);
if(p == nil)
- sysfatal("sendclientinfo: %r");
- usize = p+ndata-a;
+ return -1;
+ usize = p+ndata-b;
q = p;
- PLONG(q+0, 0); // codePage; langId when opt&INFO_UNICODE
+ PLONG(q+0, 0); // codePage; langId when opt&InfUnicode
PLONG(q+4, opt);
PSHORT(q+8, ndom-2);
PSHORT(q+10, nusr-2);
@@ -703,182 +500,24 @@
free(wsh);
free(wwd);
- writen(rd.fd, a, usize);
-
+ return usize;
}
/* Share-Data Header (2.2.8.1.1.1.2 Share Data Header) */
-static uchar*
-putsdh(uchar* p, uchar* ep, int ndata, int pduType2)
+uchar*
+putsdh(uchar* p, uchar* ep, int ndata, int pduType2, int originid, int shareid)
{
if(p+18>ep)
sysfatal(Eshort);
PSHORT(p+0, ndata);
- PSHORT(p+2, (PDUTYPE_DATAPDU | 0x10));
- PSHORT(p+4, rd.userchan);
- PLONG(p+6, rd.shareid);
- p[10] = 0;
- p[11] = 1;
- PSHORT(p+12, ndata); // rdesktop used to put ndata-14...
+ PSHORT(p+2, (PDUdata | (1<<4)));
+ PSHORT(p+4, originid);
+ PLONG(p+6, shareid);
+ p[10] = 0; // pad1
+ p[11] = 1; // streamId: 1=Low, 2=Medium, 4=High
+ PSHORT(p+12, ndata);
p[14] = pduType2;
- p[15] = 0; // ctype
- PSHORT(p+16, 0); // clen
+ p[15] = 0; // compressedType
+ PSHORT(p+16, 0); // compressedLength
return p+18;
}
-
-/* 2.2.1.14 Client Synchronize PDU */
-static void
-assync(void)
-{
- uchar a[64], *p, *q;
- int ndata, usize;
-
- ndata = 4+SCDSIZE;
- p = prebuf(a, sizeof(a), ndata, 0, 0);
- if(p == nil)
- sysfatal("buffer not prepared: %r");
- usize = p+ndata-a;
-
- q = putsdh(p, p+ndata, ndata, PDUTYPE2_SYNCHRONIZE);
- PSHORT(q+0, 1);
- PSHORT(q+2, 1002); // target MCS userId
- writen(rd.fd, a, usize);
-}
-
-/* 2.2.1.15.1 Control PDU Data (TS_CONTROL_PDU) */
-static void
-asctl(int action)
-{
- uchar a[64], *p, *q;
- int ndata, usize;
-
- ndata = 8+SCDSIZE;
- p = prebuf(a, sizeof(a), ndata, 0, 0);
- if(p == nil)
- sysfatal("buffer not prepared: %r");
- usize = p+ndata-a;
-
- q = putsdh(p, p+ndata, ndata, PDUTYPE2_CONTROL);
- PSHORT(q+0, action);
- PSHORT(q+2, 0); // grantId[2]
- PLONG(q+4, 0); // controlId[2]
- writen(rd.fd, a, usize);
-}
-
-/* 2.2.1.18 Client Font List PDU */
-static void
-asfontls(void)
-{
- uchar a[64], *p, *q;
- int ndata, usize;
-
- ndata = 8+SCDSIZE;
- p = prebuf(a, sizeof(a), ndata, 0, 0);
- if(p == nil)
- sysfatal("buffer not prepared: %r");
- usize = p+ndata-a;
-
- q = putsdh(p, p+ndata, ndata, PDUTYPE2_FONTLIST);
- PSHORT(q+0, 0); // numberFonts
- PSHORT(q+2, 0); // totalNumFonts
- PSHORT(q+4, 2+1); // listFlags: 1=first, 2=last
- PSHORT(q+6, 50); // entrySize
-
- writen(rd.fd, a, usize);
-}
-
-/* 2.2.8.1.1.3.1.1 Slow-Path Input Event (TS_INPUT_EVENT) */
-void
-passinput(ulong msec, int mtype, int iflags, int iarg1, int iarg2)
-{
- uchar a[64], *p, *q;
- int ndata, usize;
-
- ndata = 16+SCDSIZE;
- p = prebuf(a, sizeof(a), ndata, 0, 0);
- if(p == nil)
- sysfatal("buffer not prepared: %r");
- usize = p+ndata-a;
-
- q = putsdh(p, p+ndata, ndata, PDUTYPE2_INPUT);
- PSHORT(q+0, 1); // numEvents
- PSHORT(q+2, 0);
- // 2.2.8.1.1.3.1.1 Slow-Path Input Event
- PLONG(q+4, msec);
- PSHORT(q+8, mtype);
- // slowPathInputData[*]
- PSHORT(q+10, iflags);
- PSHORT(q+12, iarg1);
- PSHORT(q+14, iarg2);
-
- writen(rd.fd, a, usize);
-}
-
-/* 2.2.11.3.1 Suppress Output PDU Data (TS_SUPPRESS_OUTPUT_PDU) */
-void
-turnupdates(int allow)
-{
- uchar a[64], *p, *q;
- int ndata, usize;
-
- ndata = (allow?12:4)+SCDSIZE;
- p = prebuf(a, sizeof(a), ndata, 0, 0);
- if(p == nil)
- sysfatal("buffer not prepared: %r");
- usize = p+ndata-a;
-
- q = putsdh(p, p+ndata, ndata, PDUTYPE2_SUPPRESS_OUTPUT);
- q[0] = (allow?1:0);
- memset(q+1, 3, 0);
- if(allow){
- PSHORT(q+4, 0); // left
- PSHORT(q+6, 0); // top
- PSHORT(q+8, rd.dim.x-1); // right
- PSHORT(q+10, rd.dim.y-1); // bottom
- }
- writen(rd.fd, a, usize);
-}
-
-int
-sizesechdr(int secflags)
-{
- if(secflags&Scrypt)
- return 12; // flags[4] mac[8]
- else if(secflags)
- return 4; // flags[4]
- return 0;
-}
-
-uchar*
-prebuf(uchar* buf, int nb, int ndata, int chanid, int secflags)
-{
- int n, len, shdsize;
- uchar *p, *ep;
-
- if(chanid==0)
- chanid = GLOBALCHAN;
-
- shdsize = sizesechdr(secflags);
- len = TPDATAFIXLEN+8+shdsize+ndata;
- if(len>nb){
- werrstr("%s: provided %d, need %d, data %d", Esmall, nb, len, ndata);
- return nil;
- }
- ep = buf+len;
-
- ndata = len-TPDATAFIXLEN;
- n = mktpdat(buf, nb, ndata);
- if(n < 0)
- sysfatal("mktpdat: %r");
- p = buf+TPDATAFIXLEN;
-
- ndata -= 8;
- if(mkmcssdr(p, ep-p, ndata, chanid) < 0)
- sysfatal("mkmcssdr: %r");
- p += 8;
-
- if(shdsize > 0)
- PLONG(p, secflags);
- return p + shdsize;
-}
-
--- /dev/null
+++ b/msg.c
@@ -1,0 +1,452 @@
+#include <u.h>
+#include <libc.h>
+#include <draw.h>
+#include "dat.h"
+#include "fns.h"
+
+enum /* Rdpnego.type */
+{
+ Tnego= 1,
+ Rnego= 2,
+};
+
+typedef struct Rdpnego Rdpnego;
+struct Rdpnego
+{
+ int type;
+ int flags;
+ int proto;
+};
+
+static int
+putnego(uchar* b, uint nb, Rdpnego* m)
+{
+ int len;
+
+ len = 8;
+ if(nb < 8){
+ werrstr(Esmall);
+ return -1;
+ }
+ b[0] = m->type;
+ b[1] = m->flags;
+ PSHORT(b+2, len);
+ PLONG(b+4, m->proto);
+
+ return len;
+}
+
+static int
+getnego(Rdpnego* m, uchar* b, uint nb)
+{
+ int len;
+
+ if(nb < 8){
+ werrstr(Eshort);
+ return -1;
+ }
+ m->type = b[0];
+ m->flags = b[1];
+ len = GSHORT(b+2);
+ m->proto = GLONG(b+4);
+ if(len != 8){
+ werrstr("bad length in RDP Nego Response");
+ return -1;
+ }
+ return len;
+}
+
+int
+sizesechdr(int secflags)
+{
+ if(secflags&Scrypt)
+ return 12; // flags[4] mac[8]
+ else if(secflags)
+ return 4; // flags[4]
+ return 0;
+}
+
+uchar*
+txprep(uchar* buf, int nb, int ndata, int chanid, int mcsuid, int secflags)
+{
+ int n, len, shdsize;
+ uchar *p, *ep;
+
+ if(chanid==0)
+ chanid = GLOBALCHAN;
+
+ shdsize = sizesechdr(secflags);
+ len = TPDATAFIXLEN+8+shdsize+ndata;
+ if(len>nb){
+ werrstr("%s: provided %d, need %d, data %d", Esmall, nb, len, ndata);
+ return nil;
+ }
+ ep = buf+len;
+
+ ndata = len-TPDATAFIXLEN;
+ n = mktpdat(buf, nb, ndata);
+ if(n < 0)
+ sysfatal("mktpdat: %r");
+ p = buf+TPDATAFIXLEN;
+
+ ndata -= 8;
+ if(putmsdr(p, ep-p, ndata, chanid, mcsuid) < 0)
+ sysfatal("putmsdr: %r");
+ p += 8;
+
+ if(shdsize > 0)
+ PLONG(p, secflags);
+ return p + shdsize;
+}
+
+int
+putmsg(uchar* b, uint nb, Msg* m)
+{
+ int n, nld, len;
+ uchar *p, *ep, *q;
+ Rdpnego neg;
+
+ switch(m->type){
+ case Xconnect:
+ /* 5.4.2.1 Negotiation-Based Approach */
+ nld = 25+8;
+ n = mktpcr(b, nb, nld);
+ if(n < 0)
+ return -1;
+ p = b+n-nld;
+ ep = b+n;
+
+ memcpy(p, "Cookie: mstshash=eltons\r\n", 25);
+ neg = (Rdpnego){Tnego, 0, m->negproto};
+ if(putnego(p+25, ep-p, &neg) != 8){
+ werrstr("pnego failed: %r");
+ return -1;
+ }
+ return n;
+
+ case Xhangup:
+ return mktpdr(b, nb, 0);
+
+ case Mattach:
+ n = mktpdat(b, nb, 1);
+ if(n < 0)
+ return -1;
+ b[TPDATAFIXLEN] = (Maur<<2);
+ return n;
+
+ case Mjoin:
+ n = mktpdat(b, nb, 5);
+ if(n < 0)
+ return -1;
+ p = b+TPDATAFIXLEN;
+ p[0] = (Mcjr << 2);
+ PSHORTB(p+1, m->mcsuid);
+ PSHORTB(p+3, m->chanid);
+ return n;
+
+ case Merectdom:
+ n = mktpdat(b, nb, 5);
+ if(n < 0)
+ return -1;
+ p = b+TPDATAFIXLEN;
+ p[0] = (Medr << 2);
+ PSHORTB(p+1, 1);
+ PSHORTB(p+3, 1);
+ return n;
+
+ case Mconnect:
+ /* 2.2.1.3 Client MCS Connect Initial PDU with GCC Conference Create Request */
+ nld = sizegccr(m);
+ len = mktpdat(b, nb, nld+MCSCIFIXLEN);
+ if(len < 0){
+ werrstr("mktpdat: %r");
+ return -1;
+ }
+ p = b+TPDATAFIXLEN;
+ ep = b+nb;
+ n = mkmcsci(p, ep-p, nld);
+ if(n != nld+MCSCIFIXLEN){
+ werrstr("mkmcsci: %r");
+ return -1;
+ }
+ n = putgccr(p+MCSCIFIXLEN, nld, m);
+ if(n != nld){
+ werrstr("putgccr: %r");
+ return -1;
+ }
+ return len;
+
+ case Dclientinfo:
+ /* 2.2.1.11 Client Info PDU */
+ return putclientinfo(b, nb, m);
+
+ case Mactivated:
+ /* 2.2.1.13.2 Client Confirm Active PDU */
+ return putconfirmactive(b, nb, m);
+
+ case Mvcdata:
+ nld = m->ndata+8;
+ p = txprep(b, nb, nld, m->chanid, m->originid, 0);
+ if(p == nil)
+ return -1;
+ PLONG(p+0, m->len);
+ PLONG(p+4, m->flags);
+ memcpy(p+8, m->data, m->ndata);
+ len = p+nld-b;
+ return len;
+
+ case Async:
+ /* 2.2.1.14 Client Synchronize PDU */
+ nld = 4+SCDSIZE;
+ if((p = txprep(b, nb, nld, 0, m->originid, 0)) == nil)
+ return -1;
+ len = p+nld-b;
+ q = putsdh(p, p+nld, nld, ADsync, m->originid, m->shareid);
+ PSHORT(q+0, 1); // sync message type
+ PSHORT(q+2, m->mcsuid); // target MCS userId
+ return len;
+
+ case Actl:
+ /* 2.2.1.15 Control PDU */
+ nld = 8+SCDSIZE;
+ if((p = txprep(b, nb, nld, 0, m->originid, 0)) == nil)
+ return -1;
+ len = p+nld-b;
+
+ q = putsdh(p, p+nld, nld, ADctl, m->originid, m->shareid);
+ /* action[2] grantId[2] controlId[2] */
+ PSHORT(q+0, m->action);
+ PSHORT(q+2, 0);
+ PLONG(q+4, 0);
+ return len;
+
+ case Afontls:
+ /* 2.2.1.18 Client Font List PDU */
+ nld = 8+SCDSIZE;
+ if((p = txprep(b, nb, nld, 0, m->originid, 0)) == nil)
+ return -1;
+ len = p+nld-b;
+
+ q = putsdh(p, p+nld, nld, ADfontlist, m->originid, m->shareid);
+ PSHORT(q+0, 0); // numberFonts
+ PSHORT(q+2, 0); // totalNumFonts
+ PSHORT(q+4, 2+1); // listFlags: 1=first, 2=last
+ PSHORT(q+6, 50); // entrySize
+ return len;
+
+ case Ainput:
+ /* 2.2.8.1.1.3.1.1 Slow-Path Input Event (TS_INPUT_EVENT) */
+ nld = 16+SCDSIZE;
+ if((p = txprep(b, nb, nld, 0, m->originid, 0)) == nil)
+ return -1;
+ len = p+nld-b;
+
+ q = putsdh(p, p+nld, nld, ADinput, m->originid, m->shareid);
+ PSHORT(q+0, 1); /* numEvents */
+ PSHORT(q+2, 0);
+ PLONG(q+4, m->msec);
+ PSHORT(q+8, m->mtype);
+ PSHORT(q+10, m->flags);
+ PSHORT(q+12, m->iarg1);
+ PSHORT(q+14, m->iarg2);
+ return len;
+
+ case Lreq:
+ case Lnolicense:
+ if((nld = sizelicensemsg(m)) < 0)
+ return -1;
+ if((p = txprep(b, nb, nld, 0, m->originid, Slicensepk)) == nil)
+ return -1;
+ len = p+nld-b;
+ if(putlicensemsg(p, nld, m) != nld){
+ werrstr("putlicensemsg: %r");
+ return -1;
+ }
+ return len;
+
+ case Dsupress:
+ /* 2.2.11.3 Suppress Output PDU */
+ nld = (m->allow?12:4)+SCDSIZE;
+ if((p = txprep(b, nb, nld, 0, m->originid, 0)) == nil)
+ return -1;
+ len = p-b+nld;
+
+ q = putsdh(p, p+nld, nld, ADsupress, m->originid, m->shareid);
+ q[0] = (m->allow?1:0);
+ memset(q+1, 3, 0);
+ if(m->allow){
+ PSHORT(q+4, 0); // left
+ PSHORT(q+6, 0); // top
+ PSHORT(q+8, m->xsz-1); // right
+ PSHORT(q+10, m->ysz-1); // bottom
+ }
+ return len;
+
+ default:
+ werrstr("putmsg: unsupported type");
+ return 0;
+ }
+};
+
+int
+getmsg(Msg* m, uchar* b, uint nb)
+{
+ uchar *p, *ep;
+ int type, mtag, btag, mr, secflg, sctlver;
+ Rdpnego neg;
+
+ p = b;
+ ep = b+nb;
+
+ if(istpkt(p, ep) == 0){
+ /*
+ * 2.2.9.1.2 Server Fast-Path Update PDU
+ * enabled with CanFastpath in General Capability Set
+ */
+ if(p[0]&(1<<7)){
+ werrstr("legacy encryption in a Fast-Path PDU");
+ return -1;
+ }
+ if(p[1]&(1<<7))
+ p += 3;
+ else
+ p += 2;
+ m->type = Aupdate;
+ m->data = p;
+ m->ndata = ep-p;
+ m->getshare = getshareF;
+ return nb;
+ }
+
+ type = tptype(b, b+nb);
+ switch(type){
+ default:
+ werrstr("unknown TPDU type %d", type);
+ return -1;
+ case ConCfrm:
+ /* 5.4.2.1 Negotiation-Based Approach */
+ m->type = Xconnected;
+ m->negproto = 0;
+ if((p = tpdat(p, ep)) != nil && getnego(&neg, p, ep-p))
+ if(neg.type == Rnego)
+ m->negproto = neg.proto;
+ return nb;
+ case Data:
+ p = tpdat(p, ep);
+ if(p+2 > ep){
+ werrstr(Eshort);
+ return -1;
+ }
+
+ /* try ASN.1 PER: DomainMCSPDU are encoded this way */
+ mtag = p[0]>>2;
+ switch(mtag){
+ default:
+ werrstr("unknown MCS tag %d", mtag);
+ return -1;
+ case Mauc:
+ m->type = Mattached;
+ m->mcsuid = 0;
+ mr = p[1];
+ if(mr != 0){
+ werrstr("Mauc error result: %d", mr);
+ return -1;
+ }
+ if((p[0])&2){
+ if(p+4 > ep){
+ werrstr(Eshort);
+ return -1;
+ }
+ m->mcsuid = GSHORTB(p+2);
+ }
+ return nb;
+ case Mcjc:
+ m->type = Mjoined;
+ mr = p[1];
+ if(mr != 0){
+ werrstr("Mcjc error result: %d", mr);
+ return -1;
+ }
+ return nb;
+ case Mdpu:
+ m->type = Mclosing;
+ return nb;
+ case Msdi:
+ m->chanid = mcschan(b, b+nb);
+ if(m->chanid < 0){
+ werrstr("%d: bad MCS channel id", m->chanid);
+ return -1;
+ }
+ p = mcsdat(b, b+nb);
+ if(p == nil)
+ return -1;
+ if(m->chanid != GLOBALCHAN){
+ m->type = Mvcdata;
+ m->len = GLONG(p+0);
+ m->flags = GLONG(p+4);
+ m->data = p+8;
+ m->ndata = ep-p-8;
+ if(m->len > 8*1024*1024){
+ werrstr("bad length in virtual channel PDU header");
+ return -1;
+ }
+ return nb;
+ }
+ if(isflowpdu(p,ep)){
+ m->type = Aflow;
+ return nb;
+ }
+ secflg = GSHORT(p);
+ sctlver = GSHORT(p+2)>>4;
+ if(secflg&Slicensepk && sctlver != 1)
+ return getlicensemsg(m, p+4, ep-(p+4));
+
+ m->type = Aupdate;
+ m->data = p;
+ m->ndata = ep-p;
+ m->getshare = getshareT;
+ return nb;
+ case 31:
+ /* try ANS.1 BER: T.125 ConnectMCSPDU are encoded this way */
+ gbtag(p, ep, &btag);
+ switch(btag){
+ case Mcr:
+ return getmcr(m, p, ep-p);
+ default:
+ werrstr("unknown MCS BER tag %d", btag);
+ return -1;
+ }
+ }
+
+ }
+};
+
+int
+readmsg(Rdp* c, Msg* m)
+{
+ uchar* buf;
+ int fd, n;
+ uint nb;
+
+ fd = c->fd;
+ buf = c->rbuf;
+ nb = sizeof c->rbuf;
+
+ if((n = readpdu(fd, buf, nb)) < 0 || getmsg(m, buf, n) <= 0)
+ return -1;
+
+ return n;
+}
+
+int
+writemsg(Rdp* c, Msg* m)
+{
+ uchar buf[MAXTPDU];
+ int fd, n;
+
+ fd = c->fd;
+ if((n = putmsg(buf, sizeof buf, m)) < 0 || writen(fd, buf, n) != n)
+ return -1;
+
+ return n;
+}
--- a/rd.c
+++ b/rd.c
@@ -7,9 +7,7 @@
Rdp rd = {
.fd = -1,
- .chan = RGB16,
.depth = 16,
- .dim = {800, 600},
.windom = "",
.passwd = "",
.shell = "",
@@ -56,7 +54,7 @@
return mpid;
}
atexit(atexitkiller);
- readdevmouse();
+ readdevmouse(&rd);
exits("mouse eof");
return 0;
}
@@ -74,7 +72,7 @@
return pid;
}
atexit(atexitkiller);
- readkbd();
+ readkbd(&rd);
exits("kbd eof");
return 0;
}
@@ -93,7 +91,8 @@
return pid;
}
atexit(atexitkiller);
- pollsnarf();
+ initsnarf();
+ pollsnarf(&rd);
exits("snarf eof");
return 0;
}
@@ -154,25 +153,6 @@
break;
case 'a':
rd.depth = atol(EARGF(usage()));
- switch(rd.depth){
- case 8:
- rd.chan = CMAP8;
- break;
- case 15:
- rd.chan = RGB15;
- break;
- case 16:
- rd.chan = RGB16;
- break;
- case 24:
- rd.chan = RGB24;
- break;
- case 32:
- rd.chan = XRGB32;
- break;
- default:
- sysfatal("bad color depth");
- }
break;
case '0':
rd.wantconsole = 1;
@@ -199,9 +179,10 @@
else {
rd.user = creds->user;
rd.passwd = creds->passwd;
- rd.autologon = 1;
}
- }
+ }else
+ rd.user = "";
+ initvc(&rd);
addr = netmkaddr(server, "tcp", "3389");
fd = dial(addr, nil, nil, nil);
@@ -208,8 +189,8 @@
if(fd < 0)
sysfatal("dial %s: %r", addr);
rd.fd = fd;
- if(x224connect(fd) < 0)
- sysfatal("initial handshake failed: %r");
+ if(x224connect(&rd) < 0)
+ sysfatal("connect: %r");
if(initdraw(drawerror, nil, rd.label) < 0)
sysfatal("initdraw: %r");
@@ -216,34 +197,199 @@
display->locking = 1;
unlockdisplay(display);
- rd.dim.y = Dy(screen->r);
- rd.dim.x = Dx(screen->r);
- rd.dim.x = (rd.dim.x + 3) & ~3; /* ensure width divides by 4 */
+ rd.ysz = Dy(screen->r);
+ rd.xsz = (Dx(screen->r) +3) & ~3;
- if(rdphandshake(fd) < 0)
- sysfatal("handshake failed: %r");
+ if(rdphandshake(&rd) < 0)
+ sysfatal("handshake: %r");
atexit(atexitkiller);
atexitkill(getpid());
atexitkill(startmouseproc());
atexitkill(startkbdproc());
- initsnarf();
atexitkill(startsnarfproc());
- readnet(rd.fd);
+ readnet(&rd);
- x224disconnect(rd.fd);
- close(rd.fd);
- lockdisplay(display);
- closedisplay(display);
+ x224disconnect(&rd);
if(!rd.active)
exits(nil);
if(rd.hupreason)
- sysfatal("hangup: %d", rd.hupreason);
+ sysfatal("disconnect reason code %d", rd.hupreason);
sysfatal("hangup");
}
+void
+readnet(Rdp* c)
+{
+ Msg r;
+
+ for(;;){
+ if(readmsg(c, &r) <= 0)
+ return;
+
+ switch(r.type){
+ case Mclosing:
+ return;
+ case Mvcdata:
+ scanvcdata(c, &r);
+ break;
+ case Aupdate:
+ scanupdates(c, &r);
+ break;
+ }
+ }
+}
+
+void
+scanupdates(Rdp* c, Msg* m)
+{
+ int n;
+ uchar *p, *ep;
+ Share u;
+
+ p = m->data;
+ ep = m->data + m->ndata;
+
+ for(; p < ep; p += n){
+ n = m->getshare(&u, p, ep-p);
+ if(n < 0)
+ sysfatal("scanupdates: %r");
+
+ switch(u.type){
+ case ShDeactivate:
+ deactivating(c, &u);
+ break;
+ case ShEinfo:
+ c->hupreason = u.err;
+ break;
+ case ShUorders:
+ scanorders(c, &u);
+ break;
+ case ShUimg:
+ scanimgupdate(c, &u);
+ break;
+ case ShUcmap:
+ scancmap(c, &u);
+ break;
+ case ShUwarp:
+ warpmouse(u.x, u.y);
+ break;
+ }
+ }
+}
+
+/* 2.2.1.13.1 Server Demand Active PDU */
+void
+activating(Rdp* c, Share* as)
+{
+ Caps rcaps;
+
+ if(getcaps(&rcaps, as->data, as->ndata) < 0)
+ sysfatal("getcaps: %r");
+ if(!rcaps.canrefresh)
+ sysfatal("server can not Refresh Rect PDU");
+ if(!rcaps.cansupress)
+ sysfatal("server can not Suppress Output PDU");
+ if(!rcaps.bitmap)
+ sysfatal("server concealed their Bitmap Capabilities");
+
+ switch(rcaps.depth){
+ default: sysfatal("Unsupported server color depth: %uhd\n", rcaps.depth);
+ case 8: c->chan = CMAP8; break;
+ case 15: c->chan = RGB15; break;
+ case 16: c->chan = RGB16; break;
+ case 24: c->chan = RGB24; break;
+ case 32: c->chan = XRGB32; break;
+ }
+ c->depth = rcaps.depth;
+ c->xsz = rcaps.xsz;
+ c->ysz = rcaps.ysz;
+ c->srvchan = as->source;
+ c->shareid = as->shareid;
+ c->active = 1;
+}
+
+void
+deactivating(Rdp* c, Share*)
+{
+ c->active = 0;
+}
+
+/* 2.2.9.1.1.3.1.2.1 Bitmap Update Data (TS_UPDATE_BITMAP_DATA) */
+void
+scanimgupdate(Rdp *c, Share* as)
+{
+ uchar* p, *ep;
+ int n, err, nr;
+ static Image* img;
+ Rectangle r, rs, d;
+ Imgupd iu;
+
+ assert(as->type == ShUimg);
+ p = as->data;
+ ep = as->data + as->ndata;
+ nr = as->nrect;
+
+ rs = rectaddpt(Rpt(ZP, Pt(c->xsz, c->ysz)), screen->r.min);
+
+ lockdisplay(display);
+
+ if(img==nil || !eqrect(img->r, rs)){
+ if(img != nil)
+ freeimage(img);
+ img = allocimage(display, rs, c->chan, 0, DNofill);
+ if(img == nil)
+ sysfatal("%r");
+ }
+
+ while(p<ep && nr>0){
+ /* 2.2.9.1.1.3.1.2.2 Bitmap Data (TS_BITMAP_DATA) */
+ if((n = getimgupd(&iu, p, ep-p)) < 0)
+ sysfatal("getimgupd: %r");
+ if(iu.depth != img->depth)
+ sysfatal("bad image depth");
+
+ d.min = Pt(iu.x, iu.y);
+ d.max = Pt(iu.xm+1, iu.ym+1);
+ r.min = ZP;
+ r.max = Pt(iu.xsz, iu.ysz);
+ r = rectaddpt(r, img->r.min);
+
+ err = (iu.iscompr? loadrle : loadbmp)(img, r, iu.bytes, iu.nbytes, c->cmap);
+ if(err < 0)
+ sysfatal("%r");
+ draw(screen, rectaddpt(d, screen->r.min), img, nil, img->r.min);
+ p += n;
+ nr--;
+ }
+ flushimage(display, 1);
+ unlockdisplay(display);
+}
+
+void
+scancmap(Rdp* c, Share* as)
+{
+ int i, n;
+ uchar *p, *ep, *cmap;
+
+ p = as->data;
+ ep = as->data + as->ndata;
+ cmap = c->cmap;
+
+ n = GSHORT(p+4);
+ p += 8;
+ if(n > sizeof(c->cmap)){
+ fprint(2, "scancmap: data too big");
+ return;
+ }
+ if(p+3*n > ep)
+ sysfatal(Eshort);
+ for(i = 0; i<n; p+=3)
+ cmap[i++] = rgb2cmap(p[0], p[1], p[2]);
+}
+
void*
emalloc(ulong n)
{
@@ -269,7 +415,7 @@
}
char*
-estrdup(const char *s)
+estrdup(char *s)
{
char *b;
--- /dev/null
+++ b/rpc.c
@@ -1,0 +1,327 @@
+#include <u.h>
+#include <libc.h>
+#include <draw.h>
+#include "dat.h"
+#include "fns.h"
+
+int mcsconnect(Rdp*);
+int attachuser(Rdp*);
+int joinchannel(Rdp*,int,int);
+
+int
+x224connect(Rdp* c)
+{
+ Msg t, r;
+
+ t.type = Xconnect;
+ t.negproto = ProtoTLS;
+ if(writemsg(c, &t) <= 0)
+ return -1;
+ if(readmsg(c, &r) <= 0)
+ return -1;
+ if(r.type != Xconnected){
+ werrstr("X.224: protocol botch");
+ return -1;
+ }
+ if(r.negproto&ProtoTLS == 0){
+ werrstr("server refused STARTTLS");
+ return -1;
+ }
+
+ if(starttls(c) < 0)
+ return -1;
+
+ c->sproto = r.negproto;
+ return 0;
+}
+
+int
+x224disconnect(Rdp* c)
+{
+ Msg t;
+
+ t.type = Xhangup;
+ return writemsg(c, &t);
+}
+
+int
+mcsconnect(Rdp* c)
+{
+ Msg t, r;
+
+ t.type = Mconnect;
+ t.ver = 0x80004; /* RDP5 */
+ t.depth = c->depth;
+ t.xsz = c->xsz;
+ t.ysz = c->ysz;
+ t.sysname = c->local;
+ t.sproto = c->sproto;
+ t.wantconsole = c->wantconsole;
+ t.vctab = c->vc;
+ t.nvc = c->nvc;
+ if(writemsg(c, &t) <= 0)
+ sysfatal("Connect Initial: writemsg: %r");
+
+ if(readmsg(c, &r) <= 0)
+ sysfatal("Connect Response: readmsg: %r");
+ if(r.type != Mconnected)
+ sysfatal("Connect Response: protocol botch");
+ if(r.ver < t.ver)
+ sysfatal("Connect Response: unsupported RDP protocol version %x", r.ver);
+
+ return 0;
+}
+
+void
+erectdom(Rdp* c)
+{
+ Msg t;
+
+ t.type = Merectdom;
+ if(writemsg(c, &t) <= 0)
+ sysfatal("Erect Domain: writemsg: %r");
+}
+
+int
+attachuser(Rdp* c)
+{
+ Msg t, r;
+
+ t.type = Mattach;
+ if(writemsg(c, &t) <= 0)
+ sysfatal("attachuser: writemsg: %r");
+ if(readmsg(c, &r) <= 0)
+ sysfatal("attachuser: readmsg: %r");
+ if(r.type != Mattached)
+ sysfatal("attachuser: protocol botch");
+
+ c->mcsuid = r.mcsuid;
+ c->userchan = r.mcsuid;
+ return 0;
+}
+
+int
+joinchannel(Rdp* c, int mcsuid, int chanid)
+{
+ Msg t, r;
+
+ t.type = Mjoin;
+ t.mcsuid = mcsuid;
+ t.chanid = chanid;
+ if(writemsg(c, &t) <= 0)
+ sysfatal("Channel Join: writemsg: %r");
+ if(readmsg(c, &r) <= 0)
+ sysfatal("Channel Join: readmsg: %r");
+ if(r.type != Mjoined)
+ sysfatal("Channel Join: protocol botch");
+
+ /* BUG: ensure the returned and requested chanids match */
+
+ return 0;
+}
+
+int
+rdphandshake(Rdp* c)
+{
+ int i;
+ int mcsuid, userchan;
+ Vchan* v;
+ int nv;
+ Msg r;
+ Share u;
+
+ v = c->vc;
+ nv = c->nvc;
+
+ if(mcsconnect(c) < 0)
+ return -1;
+ erectdom(c);
+ if(attachuser(c) < 0)
+ return -1;
+
+ mcsuid = c->mcsuid;
+ userchan = c->userchan;
+
+ if(joinchannel(c, mcsuid, userchan) < 0)
+ return -1;
+ if(joinchannel(c, mcsuid, GLOBALCHAN) < 0)
+ return -1;
+ for(i = 0; i < nv; i++)
+ if(joinchannel(c, mcsuid, v[i].mcsid) < 0)
+ return -1;
+
+ sendclientinfo(c);
+ for(;;){
+ if(readmsg(c, &r) <= 0)
+ return -1;
+ switch(r.type){
+ case Mclosing:
+ werrstr("Disconnect Provider Ultimatum");
+ return -1;
+ case Aflow:
+ case Ldone:
+ break;
+ case Lneedlicense:
+ case Lhavechal:
+ respondlicense(c, &r);
+ break;
+ case Aupdate:
+ if(r.getshare(&u, r.data, r.ndata) < 0)
+ return -1;
+ switch(u.type){
+ case ShEinfo:
+ c->hupreason = u.err;
+ break;
+ case ShActivate:
+ activating(c, &u);
+ confirmactive(c);
+ passinput(c, 0, InputSync, 0, 0, 0);
+ assync(c);
+ asctl(c, CAcooperate);
+ asctl(c, CAreqctl);
+ asfontls(c);
+ break;
+ case ShDeactivate:
+ deactivating(c, &u);
+ break;
+ case ShSync:
+ case ShCtl:
+ break;
+ case ShFmap:
+ return 0;
+ break;
+ }
+ }
+ }
+}
+
+void
+sendclientinfo(Rdp* c)
+{
+ Msg t;
+
+ t.type = Dclientinfo;
+ t.mcsuid = c->mcsuid;
+ t.dom = c->windom;
+ t.user = c->user;
+ t.pass = c->passwd;
+ t.rshell = c->shell;
+ t.rwd = c->rwd;
+ t.dologin = (strlen(c->user) > 0);
+
+ if(writemsg(c, &t) <= 0)
+ sysfatal("sendclientinfo: %r");
+}
+
+void
+confirmactive(Rdp* c)
+{
+ Msg t;
+
+ t.type = Mactivated;
+ t.originid = c->srvchan;
+ t.mcsuid = c->userchan;
+ t.shareid = c->shareid;
+ t.xsz = c->xsz;
+ t.ysz = c->ysz;
+ t.depth = c->depth;
+ if(writemsg(c, &t) <= 0)
+ sysfatal("confirmactive: %r");
+}
+
+void
+respondlicense(Rdp *c, Msg *r)
+{
+ Msg t;
+
+ switch(r->type){
+ default:
+ return;
+ case Lneedlicense:
+ t.type = Lreq;
+ t.sysname = c->local;
+ t.user = c->user;
+ t.originid = c->userchan;
+ break;
+ case Lhavechal:
+ fprint(2, "unhandled Lhavechal\n");
+ t.type = Lnolicense;
+ t.originid = c->userchan;
+ break;
+ }
+
+ if(writemsg(c, &t) < 0)
+ sysfatal("respondlicense: writemsg failed: %r");
+}
+
+
+void
+assync(Rdp *c)
+{
+ Msg t;
+
+ t.type = Async;
+ t.mcsuid = c->srvchan;
+ t.originid = c->userchan;
+ t.shareid = c->shareid;
+ if(writemsg(c, &t) <= 0)
+ sysfatal("assync: %r");
+}
+
+void
+asctl(Rdp* c, int action)
+{
+ Msg t;
+
+ t.type = Actl;
+ t.originid = c->userchan;
+ t.shareid = c->shareid;
+ t.action = action;
+ if(writemsg(c, &t) <= 0)
+ sysfatal("asctl: %r");
+}
+
+void
+asfontls(Rdp* c)
+{
+ Msg t;
+
+ t.type = Afontls;
+ t.originid = c->userchan;
+ t.shareid = c->shareid;
+ if(writemsg(c, &t) <= 0)
+ sysfatal("asfontls: %r");
+}
+
+void
+passinput(Rdp* c, ulong msec, int mtype, int iflags, int iarg1, int iarg2)
+{
+ Msg t;
+
+ t.type = Ainput;
+ t.originid = c->userchan;
+ t.shareid = c->shareid;
+ t.mtype = mtype;
+ t.msec = msec;
+ t.flags = iflags;
+ t.iarg1 = iarg1;
+ t.iarg2 = iarg2;
+ if(writemsg(c, &t) <= 0)
+ sysfatal("passinput: %r");
+}
+
+void
+turnupdates(Rdp* c, int allow)
+{
+ Msg t;
+
+ t.type = Dsupress;
+ t.originid = c->userchan;
+ t.shareid = c->shareid;
+ t.xsz = c->xsz;
+ t.ysz = c->ysz;
+ t.allow = allow;
+ writemsg(c, &t);
+}
+
+
--- /dev/null
+++ b/tls.c
@@ -1,0 +1,54 @@
+#include <u.h>
+#include <libc.h>
+#include <draw.h>
+#include <mp.h>
+#include <libsec.h>
+#include "dat.h"
+#include "fns.h"
+
+int
+istrusted(uchar* cert, int certlen)
+{
+ uchar digest[SHA1dlen];
+ Thumbprint *table;
+
+ fmtinstall('H', encodefmt);
+ if(cert==nil || certlen <= 0) {
+ werrstr("server did not provide TLS certificate");
+ return 0;
+ }
+ sha1(cert, certlen, digest, nil);
+ table = initThumbprints("/sys/lib/tls/rdp", "/sys/lib/tls/rdp.exclude");
+ if(!table || !okThumbprint(digest, table)){
+ werrstr("server certificate %.*H not recognized", SHA1dlen, digest);
+ return 0;
+ }
+ freeThumbprints(table);
+ return 1;
+}
+
+/* lifted from /sys/src/cmd/upas/fs/imap4.c:/^starttls */
+int
+starttls(Rdp* r)
+{
+ TLSconn c;
+ int fd, sfd;
+
+ fd = r->fd;
+
+ memset(&c, 0, sizeof c);
+ sfd = tlsClient(fd, &c);
+ if(sfd < 0){
+ werrstr("tlsClient: %r");
+ return -1;
+ }
+ if(!istrusted(c.cert, c.certlen)){
+ close(sfd);
+ return -1;
+ }
+ /* BUG: free c.cert? */
+
+ close(r->fd);
+ r->fd = sfd;
+ return sfd;
+}
--- a/vchan.c
+++ b/vchan.c
@@ -10,19 +10,17 @@
enum
{
- /* 2.2.1.3.4.1 Channel Definition Structure */
- ChanInited = 0x80000000,
- ChanShowproto = 0x00200000,
+ ChanInited= 0x80000000, /* 2.2.1.3.4.1 Channel Definition Structure */
+ ChanShowproto= 0x00200000,
+
+ ChanChunkLen= 1600, /* 2.2.6.1 Virtual Channel PDU */
- /* 2.2.6.1 Virtual Channel PDU */
- ChanChunkLen = 1600,
-
- /* 2.2.6.1.1 Channel PDU Header */
- CFfirst= 0x01,
+ CFfirst= 0x01, /* 2.2.6.1.1 Channel PDU Header */
CFlast= 0x02,
CFshowproto= 0x10,
};
+static
Vchan vctab[] =
{
{
@@ -32,9 +30,17 @@
.flags = ChanInited | ChanShowproto,
},
};
+static
uint nvc = nelem(vctab);
-Vchan*
+void
+initvc(Rdp* c)
+{
+ c->vc = vctab;
+ c->nvc = nvc;
+}
+
+static Vchan*
lookupvc(int mcsid)
{
int i;
@@ -44,7 +50,7 @@
return nil;
}
-Vchan*
+static Vchan*
namevc(char* name)
{
int i;
@@ -55,78 +61,58 @@
}
void
-scanvcpdu(uchar *p, uchar* ep, int chanid)
+scanvcdata(Rdp* c, Msg* m)
{
- int flags, len, rem;
- uchar *q, *eq;
Vchan* vc;
-
- vc = lookupvc(chanid);
+ int n;
+
+ vc = lookupvc(m->chanid);
if(vc == nil)
return;
- len = GLONG(p+0);
- flags = GLONG(p+4);
- p += 8;
- if(len < 0 || len > 8*1024*1024){
- werrstr("bad length in virtual channel PDU header");
- fprint(2, "scanvcpdu: %r\n");
- return;
- }
- if(flags&CFfirst){
- vc->defragging = 1;
+ if(m->flags&CFfirst)
vc->pos = 0;
- }
- if(!vc->defragging){
- vc->fn(p, ep);
- return;
- }
+ vc->buf = erealloc(vc->buf, m->len);
+ vc->nb = m->len;
+ n = vc->nb - vc->pos;
+ if(n > m->ndata)
+ n = m->ndata;
+ memcpy(vc->buf+vc->pos, m->data, n);
+ vc->pos += n;
- vc->buf = erealloc(vc->buf, len);
- vc->nb = len;
- q = vc->buf + vc->pos;
- eq = vc->buf + len;
- rem = ep-p;
- if(rem > eq-q)
- rem = eq-q;
- memcpy(q, p, rem);
- vc->pos += rem;
- if(flags&CFlast){
- q = vc->buf;
- vc->fn(q, eq);
+ if(m->flags&CFlast){
+ vc->fn(c, vc->buf, vc->nb);
free(vc->buf);
vc->buf = nil;
vc->nb = 0;
- vc->defragging = 0;
}
}
int
-sendvc(char* cname, uchar* a, int n)
+sendvc(Rdp* c, char* cname, uchar* a, int n)
{
int sofar, chunk;
- int flags;
- int nb, len, ndata;
- uchar buf[40+ChanChunkLen];
- uchar *p, *q;
Vchan* vc;
- int chanid;
+ Msg t;
+ if(n < 0)
+ return -1;
+
vc = namevc(cname);
if(vc == nil){
werrstr("%s: no such vchannel", cname);
return -1;
}
- chanid = vc->mcsid;
- if(chanid < 0)
+ if(vc->mcsid < 0)
return -1;
- if(n < 0)
- return -1;
- p = a;
- nb = sizeof(buf);
- flags = CFfirst | CFshowproto;
+ t.type = Mvcdata;
+ t.originid = c->userchan;
+ t.chanid = vc->mcsid;
+ t.flags = CFfirst | CFshowproto;
+ t.len = n;
+ t.data = a;
for(sofar=0; sofar<n; sofar += chunk){
chunk = n-sofar;
@@ -133,17 +119,14 @@
if(chunk > ChanChunkLen)
chunk = ChanChunkLen;
else
- flags |= CFlast;
- ndata = chunk+8;
- q = prebuf(buf, nb, ndata, chanid, 0);
- if(q == nil)
- return -1;
- PLONG(q+0, n);
- PLONG(q+4, flags);
- memcpy(q+8, p+sofar, chunk);
- len = q-buf+ndata;
- writen(rd.fd, buf, len);
- flags &= ~CFfirst;
+ t.flags |= CFlast;
+
+ t.data = a+sofar;
+ t.ndata = chunk;
+ writemsg(c, &t);
+
+ t.flags &= ~CFfirst;
}
return n;
}
+
--- a/wsys.c
+++ b/wsys.c
@@ -35,7 +35,7 @@
}
void
-eresized(int)
+eresized(Rdp* c, int)
{
int fd;
Point d;
@@ -45,8 +45,7 @@
sysfatal("resize failed: %r");
/* lifted from /sys/src/cmd/vnc/wsys.c */
- d = addpt(rd.dim, Pt(2*Borderwidth, 2*Borderwidth));
- rd.dim.x = (rd.dim.x + 3) & ~3; /* ensure width divides by 4 */
+ d = addpt(Pt(c->xsz, c->ysz), Pt(2*Borderwidth, 2*Borderwidth));
if(d.x < Dx(screen->r) || d.y < Dy(screen->r)){
fd = open("/dev/wctl", OWRITE);
if(fd >= 0){
@@ -54,8 +53,8 @@
close(fd);
}
}
- turnupdates(0);
- turnupdates(!ishidden());
+ turnupdates(c, 0);
+ turnupdates(c, !ishidden());
unlockdisplay(display);
}
void
@@ -113,7 +112,7 @@
/* lifted from /sys/src/cmd/vnc/wsys.c */
void
-pollsnarf(void)
+pollsnarf(Rdp* c)
{
Dir *dir;
@@ -130,7 +129,7 @@
if(dir == nil) /* old drawterm */
continue;
if(dir->qid.vers > snarfvers){
- clipannounce();
+ clipannounce(c);
snarfvers = dir->qid.vers;
}
free(dir);
--- a/x224.c
+++ b/x224.c
@@ -1,41 +1,11 @@
#include <u.h>
#include <libc.h>
#include <draw.h>
-#include <mp.h>
-#include <libsec.h>
#include "dat.h"
#include "fns.h"
-enum
-{
- /* X.224 PDU codes */
- ConReq= 0xE0, /* connection request */
- ConCfrm= 0xD0, /* connection confirm */
- HupReq= 0x80, /* disconnection request */
- Data= 0xF0, /* data */
- Err= 0x70, /* error */
-
- /* Rdpnego.type */
- Tnego= 1,
- Rnego= 2,
-
- /* Rdpnego.proto */
- ProtoTLS= 1,
- ProtoCSSP= 2,
- ProtoUAUTH= 8,
-};
-
-struct Rdpnego
-{
- int type;
- int flags;
- int proto;
-};
-int getnego(Rdpnego*, uchar*, uint);
-int putnego(uchar*, uint, Rdpnego*);
-
/*
- * examine a packet header at between p and ep
+ * examine a packet header
* returns 1 if it's a TPKT-encapsulated TPDU (T.123 clause 8; RFC 1006)
* returns 0 if not - likely a Fast-Path Update PDU ([MS-RDPBCGR] 5.3.8 and 5.4.4)
*/
@@ -54,7 +24,7 @@
}
int
-tpdutype(uchar* p, uchar* ep)
+tptype(uchar* p, uchar* ep)
{
if(p+5 >= ep){
werrstr(Eshort);
@@ -64,9 +34,9 @@
}
int
-isdatatpdu(uchar* p, uchar* ep)
+istpdat(uchar* p, uchar* ep)
{
- return (tpdutype(p,ep) == Data);
+ return (tptype(p,ep) == Data);
}
@@ -113,7 +83,7 @@
}
uchar*
-tpdupayload(uchar* p, uchar* ep)
+tpdat(uchar* p, uchar* ep)
{
uchar* q;
@@ -121,7 +91,7 @@
werrstr("Fast-Path Update PDU is not expected");
return nil;
}
- if(tpdutype(p,ep) == Data)
+ if(tptype(p,ep) == Data)
q = p+7;
else
q = p+11;
@@ -146,12 +116,14 @@
return -1;
}
- /* TPKT header: version[1] unused[1] len[2] */
+ /*
+ * TPKT header: version[1] unused[1] len[2]
+ * ConReq: hdlen[1] type[1] dstref[2] srcref[2] class[1]
+ */
p[0] = 0x03;
p[1] = 0;
PSHORTB(p+2, size);
- /* ConReq: hdlen[1] type[1] dstref[2] srcref[2] class[1] */
p[4+0] = 7-1+ndata;
p[4+1] = ConReq;
PSHORTB(p+4+2, 0);
@@ -212,153 +184,4 @@
p[5] = HupReq;
p[6] = (1<<7); /* seqno (0 in Class 0) + EOT mark (1<<7) */
return size;
-}
-
-
-int
-putnego(uchar* b, uint nb, Rdpnego* m)
-{
- int len;
-
- len = 8;
- if(nb < 8){
- werrstr(Esmall);
- return -1;
- }
- b[0] = m->type;
- b[1] = m->flags;
- PSHORT(b+2, len);
- PLONG(b+4, m->proto);
-
- return len;
-}
-
-int
-getnego(Rdpnego* m, uchar* b, uint nb)
-{
- int len;
-
- if(nb < 8){
- werrstr(Eshort);
- return -1;
- }
- m->type = b[0];
- m->flags = b[1];
- len = GSHORT(b+2);
- m->proto = GLONG(b+4);
- if(len != 8){
- werrstr("bad length in RDP Nego Response");
- return -1;
- }
- return len;
-}
-
-int
-istrusted(uchar* cert, int certlen)
-{
- uchar digest[SHA1dlen];
- Thumbprint *table;
-
- if(cert==nil || certlen <= 0) {
- werrstr("server did not provide TLS certificate");
- return 0;
- }
- sha1(cert, certlen, digest, nil);
- table = initThumbprints("/sys/lib/tls/rdp", "/sys/lib/tls/rdp.exclude");
- if(!table || !okThumbprint(digest, table)){
- werrstr("server certificate %.*H not recognized", SHA1dlen, digest);
- return 0;
- }
- freeThumbprints(table);
- return 1;
-}
-
-/* lifted from /sys/src/cmd/upas/fs/imap4.c:/^starttls */
-int
-starttls(void)
-{
- TLSconn conn;
- int sfd;
-
- fmtinstall('H', encodefmt);
- memset(&conn, 0, sizeof conn);
- sfd = tlsClient(rd.fd, &conn);
- if(sfd < 0){
- werrstr("tlsClient: %r");
- return -1;
- }
- if(!istrusted(conn.cert, conn.certlen)){
- close(sfd);
- return -1;
- }
-
- close(rd.fd);
- rd.fd = sfd;
-
- return sfd;
-}
-
-/* 5.4.2.1 Negotiation-Based Approach */
-int
-x224connect(int fd)
-{
- int n, ndata;
- uchar buf[4+7+25+8], *p, *ep;
- Rdpnego t, r;
-
- ndata = 25+8;
- n = mktpcr(buf, sizeof buf, ndata);
- if(n < 0)
- return -1;
-
- p = buf+n-ndata;
- ep = buf+n;
-
- memcpy(p, "Cookie: mstshash=eltons\r\n", 25);
- p += 25;
-
- t = (Rdpnego){Tnego, 0, ProtoTLS};
- if(putnego(p, ep-p, &t) != 8){
- werrstr("pnego failed: %r");
- return -1;
- }
- if(writen(fd, buf, n) != n)
- return -1;
-
- n = readpdu(fd, buf, sizeof buf);
- if(n < 6){
- werrstr("X.224: ConCfrm: %r");
- return -1;
- }
- ep = buf+n;
-
- if(!istpkt(buf, ep) || tpdutype(buf, ep) != ConCfrm){
- werrstr("X.224: protocol botch");
- return -1;
- }
- if((p = tpdupayload(buf, ep)) == nil)
- return -1;
- if(getnego(&r, p, ep-p) < 0 || r.type != Rnego || !(r.proto&ProtoTLS)){
- werrstr("server refused STARTTLS");
- return -1;
- }
-
- fd = starttls();
- if(fd < 0)
- return -1;
-
- rd.sproto = r.proto;
-
- return fd;
-}
-
-int
-x224disconnect(int fd)
-{
- int n, m;
- uchar buf[12];
-
- n = mktpdr(buf, sizeof buf, 0);
- m = write(fd, buf, n);
- return m;
}