#include "rdp.h" Rdp* rdpinit(int dfd) { Rdp* r; Vchan* vc; r = mallocz(sizeof(Rdp), 1); r->dfd = dfd; r->myname = getenv("sysname"); r->width = 640; r->height = 480; r->bpp = 24; /* US keyboard layout */ r->kbdlayout = 0x409; r->kbdtype = 0x04; r->kbdsubtype = 0x00; r->kbdfkeys = 12; vc = mallocz(sizeof(Vchan), 1); vc->name = "cliprdr"; r->chan = vc; r->nchan = 1; return r; } /* assembles RDP clientCoreData structure */ int mkrdpclncd(Rdp* s, uchar* buf, int nbuf) { int i, n; uchar *p; char* a; Rune *u; if(nbuf < RDPCLNCDFIXLEN) return -1; p = buf; /* GCC User Data block header (TS_UD_HEADER) */ PBIT16(p, 0xC001); /* User Data Header type: CS_CORE */ p += BIT16SZ; PBIT16(p, RDPCLNCDFIXLEN); /* userData length with header */ p += BIT16SZ; PBIT32(p, 0x00080004); /* version: RDP5; RDP4 is 0x00080001 */ p += BIT32SZ; PBIT16(p, s->width); /* desktopWidth ≤ 4096 */ p += BIT16SZ; PBIT16(p, s->height); /* desktopHeight ≤ 2048 */ p += BIT16SZ; PBIT16(p, 0xCA01); /* colorDepth, ignored: see postBeta2ColorDepth */ p += BIT16SZ; PBIT16(p, 0xAA03); /* SASSequence: RND_UD_SAS_DEL */ p += BIT16SZ; PBIT32(p, s->kbdlayout); /* keyboardLayout: en-us */ p += BIT32SZ; PBIT32(p, 2600); /* clientBuild… */ p += BIT32SZ; n = utflen(s->myname); if(n > 15){ werrstr("client name is too long"); return -1; } /* clientName: 16 runes including terminating null */ u = (Rune*)p; a = s->myname; for(i=0; ikbdtype); /* keyboardType */ p += BIT32SZ; PBIT32(p, s->kbdsubtype); /* keyboardSubType */ p += BIT32SZ; PBIT32(p, s->kbdfkeys); /* keyboardFunctionKey */ p += BIT32SZ; PBIT16(p, 0); /* imeFileName, 32 runes */ p += 32*BIT16SZ; PBIT16(p, 0xCA01); /* postBeta2ColorDepth (8pp), ignored: see highColorDepth */ p += BIT16SZ; PBIT16(p, 1); /* clientProductID */ p += BIT16SZ; PBIT32(p, 0); /* serialNumber */ p += BIT32SZ; PBIT16(p, (s->bpp<24?s->bpp:24)); /* highColorDepth: 4, 8, 15, 16, 24 bpp. */ p += BIT16SZ; PBIT16(p, 1+2); /* supportedColorDepths: 1=24, 2=16, 4=15, 8=32 bpp. */ p += BIT16SZ; PBIT16(p, (s->bpp==32? 2:0)); /* earlyCapabilityFlags */ p += BIT16SZ; PBIT16(p, 0); /* clientDigProductId, 64 bytes */ p += 64*BIT8SZ; PBIT16(p, 0); /* pad2octets */ p += BIT16SZ; USED(p); return RDPCLNCDFIXLEN; } /* assembles RDP clientSecurityData structure (2.2.1.3.3) */ int mkrdpclnsd(Rdp* s, uchar* buf, int nbuf) { uchar *p; p = buf; USED(s); if(nbuf < RDPCLNSDFIXLEN){ werrstr("buffer too small"); return -1; } /* GCC User Data block header (TS_UD_HEADER) */ PBIT16(p, 0xC002); /* User Data Header type: CS_SECURITY */ p += BIT16SZ; PBIT16(p, RDPCLNSDFIXLEN); /* userData length with header */ p += BIT16SZ; PBIT32(p, 3); /* encryptionMethods: 1=rc4 40bit; 2=rc4 128bit; 8=rc4 56bit; 16=request compliance to FIPS 140-1 */ p += BIT32SZ; PBIT32(p, 0); /* extEncryptionMethods */ p += BIT32SZ; USED(p); return RDPCLNSDFIXLEN; } /* estimates size an RDP clientNetworkData structure would take */ int sizerdpclnnd(Rdp* s) { return 2*BIT16SZ+BIT32SZ+(s->nchan*(8*BIT8SZ+BIT32SZ)); } /* assembles RDP clientNetworkData structure */ int mkrdpclnnd(Rdp* s, uchar* buf, int nbuf) { uchar *p; Vchan *vc; int i, len; p = buf; len = sizerdpclnnd(s); if(nbuf < len){ werrstr("buffer too small"); return -1; } /* GCC User Data block header (TS_UD_HEADER) */ PBIT16(p, 0xC003); /* User Data Header type: CS_NET*/ p += BIT16SZ; PBIT16(p, len); /* userData length with header */ p += BIT16SZ; PBIT32(p, s->nchan); /* channelCount */ p += BIT32SZ; vc = s->chan; for(i=0; i < s->nchan; i++, vc=vc->next){ strncpy((char*)p, vc->name, 8); /* name: 7 ANSI characters plus null */ p += 8*BIT8SZ; PBIT32(p, 0); /* options */ p += BIT32SZ; } return len; } /* assembles RDP clientClusterData structure */ int mkrdpclncld(Rdp* s, uchar* buf, int nbuf) { uchar *p; p = buf; USED(s); if(nbuf < RDPCLNCLDFIXLEN){ werrstr("buffer too small"); return -1; } /* GCC User Data block header (TS_UD_HEADER) */ PBIT16(p, 0xC004); /* User Data Header type: CS_CLUSTER */ p += BIT16SZ; PBIT16(p, RDPCLNCLDFIXLEN); /* userData length with header */ p += BIT16SZ; PBIT32(p, 0); /* Flags */ p += BIT32SZ; PBIT32(p, 0); /* RedirectedSessionID */ p += BIT32SZ; USED(p); return RDPCLNCLDFIXLEN; } /* build a MCS Connect-Initial package as a X.221 DT TPDU: TPKT header MCS CI header GSS CCrq header RDP clncd RDP clnsd RDP clnnd var size RDP clncld */ int mkrdpci(Rdp* r, uchar* buf, int nbuf) { int size, rlen, n; uchar *p, *ep; p = buf; ep = buf + nbuf; rlen = RDPCLNCDFIXLEN+RDPCLNSDFIXLEN+sizerdpclnnd(r)+RDPCLNCLDFIXLEN; size = TPDATAFIXLEN+MCSCIFIXLEN+GCCCRFIXLEN+rlen; if(nbuf < size){ werrstr("buffer too small"); return -1; } n = mktpdata(buf, nbuf, MCSCIFIXLEN+GCCCRFIXLEN+rlen); if(n < 0) return -1; p += TPDATAFIXLEN; if(mkmcsci(p, ep-p, GCCCRFIXLEN+rlen) < 0) return -1; p += MCSCIFIXLEN; if(mkgcccr(p, ep-p, rlen) < 0) return -1; p += GCCCRFIXLEN; if(mkrdpclncd(r, p, ep-p) < 0) return -1; p += RDPCLNCDFIXLEN; if(mkrdpclnsd(r, p, ep-p) < 0) return -1; p += RDPCLNSDFIXLEN; n = mkrdpclnnd(r, p, ep-p); if(n < 0) return -1; p += n; if(mkrdpclncld(r, p, ep-p) < 0) return -1; return size; } int rdphandshake(Rdp* r) { int size, n; uchar code; uchar buf[MAXTPDU], *p; /* prepare X.224 Connection Request PDU */ size = mktpcr(buf, sizeof(buf), 0); if(size < 0) sysfatal("can't make X.224 CR packet: %r"); n = write(r->dfd, buf, size); if(n < size){ werrstr("can't send X.224 CR packet: %r"); return -1; } /* expect X.224 Connection Confirm PDU */ n = readtpdu(r->dfd, buf, sizeof(buf)); if(n < 7){ werrstr("bad reply to X.224 CR received"); return -1; } p = buf + BIT32SZ; /* skip TPKT hdr */ code = GBIT8(p + BIT8SZ); /* length indicator followed by TPDU code */ if(code != TPDUCC){ werrstr("expected X.224 CC, got 0x%x", code); return -1; } /* prepare MCS Connect Initial Request PDU */ size = mkrdpci(r, buf, sizeof(buf)); if(size < 0) sysfatal("can't construct Connect-Initial packet: %r"); n = write(r->dfd, buf, size); if(n < size){ werrstr("can't send Connect-Initial packet: %r"); return -1; } /* expect MCS Connect Response PDU */ n = readtpdu(r->dfd, buf, sizeof(buf)); if(n < 7){ werrstr("bad reply to MCS CI: %r"); return -1; } p = buf + BIT32SZ; /* skip TPKT hdr and LI */ code = GBIT8(p + BIT8SZ); if (code != TPDUDT){ werrstr("expected X.224 DT, got 0x%x", code); return -1; } /* fixme: parse MCS Connect Response which is in BER */ return 0; }