/* * [MS-RDPBCGR] 3.1.5.2 Static Virtual Channels * http://msdn.microsoft.com/en-us/library/cc240926.aspx */ #include #include #include #include "dat.h" #include "fns.h" #define DBG if(0) enum { /* * 2.2.1.3.4.1 Channel Definition Structure * http://msdn.microsoft.com/en-us/library/cc240513.aspx */ CHANNEL_OPTION_INITIALIZED = 0x80000000, CHANNEL_OPTION_ENCRYPT_RDP = 0x40000000, CHANNEL_OPTION_COMPRESS_RDP = 0x00800000, CHANNEL_OPTION_SHOW_PROTOCOL = 0x00200000, /* * 2.2.6.1 Virtual Channel PDU * http://msdn.microsoft.com/en-us/library/cc240548.aspx */ CHANNEL_CHUNK_LENGTH = 1600, /* 2.2.6.1.1 Channel PDU Header */ CHANNEL_FLAG_FIRST = 0x01, CHANNEL_FLAG_LAST = 0x02, CHANNEL_FLAG_SHOW_PROTOCOL = 0x10, CFatom = CHANNEL_FLAG_FIRST | CHANNEL_FLAG_LAST, }; Vchan vctab[] = { { .mcsid = GLOBALCHAN + 1, /* iota */ .name = "CLIPRDR", .fn = clipvcfn, .flags = CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP | CHANNEL_OPTION_COMPRESS_RDP | CHANNEL_OPTION_SHOW_PROTOCOL, }, }; uint nvc = nelem(vctab); Vchan* lookupvc(int mcsid) { int i; for(i=0; i 8*1024*1024){ werrstr("bad length in virtual channel PDU header"); fprint(2, "scanvcpdu: %r\n"); return; } if((flags&CFatom) == CFatom){ vc->fn(p, ep); return; } // defragment vc->buf = erealloc(vc->buf, len); vc->nb = len; if(flags&CHANNEL_FLAG_FIRST) vc->pos = 0; q = vc->buf+vc->pos; eq = vc->buf+len; rem = ep-p; if(q+rem > eq) rem = eq-q; memcpy(q, p, rem); vc->pos += rem; if(flags&CHANNEL_FLAG_LAST){ q = vc->buf; vc->fn(q, eq); free(vc->buf); vc->buf = nil; vc->nb = 0; } } int sendvc(char* cname, uchar* a, int n) { int sofar, chunk; int flags, secflags; int nb, len, ndata; uchar buf[40+CHANNEL_CHUNK_LENGTH]; uchar *p, *q; Vchan* vc; int chanid; vc = namevc(cname); if(vc == nil){ werrstr("%s: no such vchannel", cname); return -1; } chanid = vc->mcsid; if(chanid < 0) return -1; if(n < 0) return -1; p = a; secflags = (rd.opt&OEncrypt? SEC_ENCRYPT : 0); nb = sizeof(buf); flags = CHANNEL_FLAG_FIRST | CHANNEL_FLAG_SHOW_PROTOCOL; for(sofar=0; sofar CHANNEL_CHUNK_LENGTH) chunk = CHANNEL_CHUNK_LENGTH; else flags |= CHANNEL_FLAG_LAST; ndata = chunk+8; q = prebuf(buf, nb, ndata, chanid, secflags); if(q == nil) return -1; PLONG(q+0, n); PLONG(q+4, flags); memcpy(q+8, p+sofar, chunk); if(secflags&SEC_ENCRYPT){ rdpmac(q-8, 8, q, ndata); rdpencrypt(q, ndata); } len = q-buf+ndata; writen(rd.fd, buf, len); flags &= ~CHANNEL_FLAG_FIRST; } return n; }