commit 34f82f3e18bb9f88b397323c5cc0488055b5d805 Author: Matt Chapman Date: Wed May 10 07:36:34 2000 +0000 This commit was generated by cvs2svn to compensate for changes in r2, which included commits to RCS files with non-trunk default branches. git-svn-id: svn://svn.code.sf.net/p/rdesktop/code/trunk/rdesktop@3 423420c4-83ab-492f-b58f-81f9feb106b5 diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..a43ea21 --- /dev/null +++ b/COPYING @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..5bf3d65 --- /dev/null +++ b/Makefile @@ -0,0 +1,10 @@ +############################################## +# rdesktop: A Remote Desktop Protocol client # +# Linux Makefile # +# Copyright (C) Matthew Chapman 1999-2000 # +############################################## + +SOURCES=client.c parse.c tcp.c iso.c mcs.c rdp.c bitmap.c + +rdesktop: $(SOURCES) + @gcc -g -Wall -o rdesktop $(SOURCES) diff --git a/bitmap.c b/bitmap.c new file mode 100644 index 0000000..48e56ed --- /dev/null +++ b/bitmap.c @@ -0,0 +1,263 @@ +/* + rdesktop: A Remote Desktop Protocol client. + Bitmap decompression routines + Copyright (C) Matthew Chapman 1999-2000 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" +#include + +#define BITMAP_DEBUG 1 + +#if BITMAP_DEBUG +void hexdump(char *filename, unsigned char *data, int length); +#endif + +#define RCVAL() (*(input++)) +#define RSVAL() ((*((input++) + 1) << 8) | RCVAL()) +#define SCVAL(v) {*(output++) = (v);} + +#define FILL() {while (n-- > 0) { if (output - start < width) { SCVAL(0) } else { SCVAL(*(output-width)); }}} +#define MIX() {while (n-- > 0) { if (output - start < width) { SCVAL(mix) } else { SCVAL(*(output-width) ^ mix); }}} +#define COPY() {while (n-- > 0) { SCVAL(RCVAL()); }} +#define COLOR() {int color = RCVAL(); \ + while (n-- > 0) { SCVAL(color); }} +#define BICOLOR() {int color1 = RCVAL(); int color2 = RCVAL(); \ + while (n-- > 0) { SCVAL(color1); SCVAL(color2); }} +#define SETMIX_MIX() {mix = RCVAL(); MIX();} +#define COPY_PACKED() {n++; n/=2; while (n-- > 0) \ + {unsigned char c = RCVAL(); SCVAL((c & 0xF0) >> 4); \ + SCVAL(c & 0x0F); }} + +BOOL bitmap_decompress(unsigned char *input, int size, + unsigned char *output, int width) +{ + unsigned char *savedinput = input; + unsigned char *start = output; + unsigned char *end = input + size; + unsigned char code; + unsigned char mix = 0xFF; + int n, savedn; + + while (input < end) + { + code = RCVAL(); + switch (code) + { + case 0x00: // Fill + n = RCVAL() + 32; + FILL(); + break; + case 0xF0: // Fill + n = RSVAL(); + FILL(); + break; + case 0x20: // Mix + n = RCVAL() + 32; + MIX(); + break; + case 0xF1: // Mix + n = RSVAL(); + MIX(); + break; + case 0x40: // FillOrMix + fprintf(stderr, "FillOrMix unsupported\n"); + savedn = n = RCVAL() + 1; + MIX(); + input += (savedn+7)/8; + break; + case 0xF2: + fprintf(stderr, "FillOrMix unsupported\n"); + savedn = n = RSVAL(); + MIX(); + input += (savedn+7)/8; + break; + case 0x60: // Color + n = RCVAL() + 32; + COLOR(); + break; + case 0xF3: + n = RSVAL(); + fprintf(stderr, "Color %d\n", n); + COLOR(); + break; + case 0x80: // Copy + n = RCVAL() + 32; + COPY(); + break; + case 0xF4: + n = RSVAL(); + COPY(); + break; + case 0xA0: // Copy Packed + fprintf(stderr, "CopyPacked 1\n"); + n = RCVAL() + 32; + COPY_PACKED(); + break; + case 0xF5: + fprintf(stderr, "CopyPacked 2\n"); + n = RSVAL(); + COPY_PACKED(); + break; + case 0xC0: // SetMix_Mix + fprintf(stderr, "SetMix_Mix 1\n"); + n = RCVAL() + 16; + SETMIX_MIX(); + break; + case 0xF6: + fprintf(stderr, "SetMix_Mix 2\n"); + n = RSVAL(); + SETMIX_MIX(); + break; + case 0xD0: // SetMix_FillOrMix + fprintf(stderr, "SetMix_FillOrMix unsupported\n"); + savedn = n = RCVAL() + 1; + SETMIX_MIX(); + input += (savedn+7)/8; + break; + case 0xF7: + fprintf(stderr, "SetMix_FillOrMix unsupported\n"); + savedn = n = RSVAL(); + SETMIX_MIX(); + input += (savedn+7)/8; + break; + case 0xE0: // Bicolor + fprintf(stderr, "Bicolor 1\n"); + n = RCVAL() + 16; + BICOLOR(); + break; + case 0xF8: + fprintf(stderr, "Bicolor 2\n"); + n = RSVAL(); + BICOLOR(); + break; + case 0xF9: // FillOrMix_1 + fprintf(stderr, "FillOrMix_1 unsupported\n"); + return False; + case 0xFA: // FillOrMix_2 + fprintf(stderr, "FillOrMix_2 unsupported\n"); + return False; + case 0xFD: // White + SCVAL(0xFF); + break; + case 0xFE: // Black + SCVAL(0); + break; + default: + n = code & 31; + + if (n == 0) + { + fprintf(stderr, "Undefined escape 0x%X\n", code); + return False; + } + + switch ((code >> 5) & 7) + { + case 0: // Fill + FILL(); + break; + case 1: // Mix + MIX(); + break; + case 2: // FillOrMix + fprintf(stderr, "FillOrMix unsupported\n"); + n *= 8; + savedn = n; + MIX(); + input += (savedn+7)/8; + break; + case 3: // Color + COLOR(); + break; + case 4: // Copy + COPY(); + break; + case 5: // Copy Packed + fprintf(stderr, "CopyPacked 3\n"); + COPY_PACKED(); + break; + case 6: + n = code & 15; + + switch ((code >> 4) & 15) + { + case 0xC: + fprintf(stderr, "SetMix_Mix 3\n"); + SETMIX_MIX(); + break; + case 0xD: + fprintf(stderr, "SetMix_FillOrMix unsupported\n"); + n *= 8; + savedn = n; + SETMIX_MIX(); + input += (savedn+7)/8; + break; + case 0xE: + fprintf(stderr, "Bicolor 3\n"); + BICOLOR(); + break; + default: + fprintf(stderr, "Undefined escape 0x%X\n", code); + return False; + } + } + } + } + + printf("Uncompressed size: %d\n", output - start); +#if BITMAP_DEBUG + { + static int bmpno = 1; + char filename[64]; + + snprintf(filename, sizeof(filename)-1, "in%d.raw", bmpno); + hexdump(filename, savedinput, size); + + snprintf(filename, sizeof(filename)-1, "out%d.raw", bmpno); + hexdump(filename, start, output-start); + + bmpno++; + } +#endif + + return True; +} + + +#if BITMAP_DEBUG +void hexdump(char *filename, unsigned char *data, int length) +{ + /* + int i; + + for (i = 0; i < length; i++) + { + printf("%02X ", data[i]); + + if (i % 16 == 15) + printf("\n"); + } + */ + + int fd; + + fd = open(filename, O_WRONLY|O_CREAT, 0600); + write(fd, data, length); + close(fd); +} +#endif diff --git a/client.c b/client.c new file mode 100644 index 0000000..bd8781b --- /dev/null +++ b/client.c @@ -0,0 +1,65 @@ +/* + rdesktop: A Remote Desktop Protocol client. + Protocol services - ISO layer + Copyright (C) Matthew Chapman 1999-2000 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" +#include "signal.h" + +int main(int argc, char *argv[]) +{ + HCONN conn; + + fprintf(stderr, "rdesktop: A Remote Desktop Protocol client.\n"); + fprintf(stderr, "Version 0.9.0-prealpha. Copyright (C) 1999-2000 Matt Chapman.\n\n"); + + if (argc < 2) + { + fprintf(stderr, "Usage: %s \n", argv[0]); + return 1; + } + + if ((conn = rdp_connect(argv[1])) == NULL) + return 1; + + fprintf(stderr, "Connection successful.\n"); + + rdp_disconnect(conn); + + return 0; +} + +void *xmalloc(int size) +{ + void *mem = malloc(size); + if (mem == NULL) { + fprintf(stderr, "xmalloc: Out of memory.\n"); + exit(1); + } + return mem; +} + +void *xrealloc(void *oldmem, int size) +{ + void *mem = realloc(oldmem, size); + if (mem == NULL) { + fprintf(stderr, "xrealloc: Out of memory.\n"); + exit(1); + } + return mem; +} diff --git a/includes.h b/includes.h new file mode 100644 index 0000000..de4f5bf --- /dev/null +++ b/includes.h @@ -0,0 +1,48 @@ +/* + rdesktop: A Remote Desktop Protocol client. + Global include file + Copyright (C) Matthew Chapman 1999-2000 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#define False (0) +#define True (1) + +typedef int BOOL; +typedef unsigned char uint8; +typedef unsigned short uint16; +typedef unsigned int uint32; + +#include "parse.h" +#include "tcp.h" +#include "iso.h" +#include "mcs.h" +#include "rdp.h" + +#include "proto.h" diff --git a/iso.c b/iso.c new file mode 100644 index 0000000..a309368 --- /dev/null +++ b/iso.c @@ -0,0 +1,174 @@ +/* + rdesktop: A Remote Desktop Protocol client. + Protocol services - ISO layer + Copyright (C) Matthew Chapman 1999-2000 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" + +/* Establish a connection up to the ISO layer */ +HCONN iso_connect(char *server) +{ + HCONN conn; + uint8 code; + + if ((conn = tcp_connect(server)) == NULL) + return NULL; + + iso_send_msg(conn, ISO_PDU_CR); + + if (!iso_recv_msg(conn, &code) || (code != ISO_PDU_CC)) + { + fprintf(stderr, "ISO error, expected CC\n"); + tcp_disconnect(conn); + return NULL; + } + + return conn; +} + +/* Disconnect from the ISO layer */ +void iso_disconnect(HCONN conn) +{ + iso_send_msg(conn, ISO_PDU_DR); + tcp_disconnect(conn); +} + +/* Send self-contained ISO message identified by code */ +BOOL iso_send_msg(HCONN conn, uint8 code) +{ + TPKT tpkt; + TPDU tpdu; + + iso_make_tpkt(&tpkt, 11); + iso_io_tpkt(&conn->out, &tpkt); + iso_make_tpdu(&tpdu, code); + iso_io_tpdu(&conn->out, &tpdu); + MARK_END(conn->out); + return tcp_send(conn); +} + +/* Receive a message on the ISO layer, return code */ +BOOL iso_recv_msg(HCONN conn, uint8 *code) +{ + TPDU tpdu; + TPKT tpkt; + BOOL res; + + res = tcp_recv(conn, 4); + res = res ? iso_io_tpkt(&conn->in, &tpkt) : False; + res = res ? tcp_recv(conn, tpkt.length - 4) : False; + res = res ? iso_io_tpdu(&conn->in, &tpdu) : False; + + *code = tpdu.code; + return res; +} + +/* Initialise ISO transport data packet */ +void iso_init(struct connection *conn) +{ + PUSH_LAYER(conn->out, iso_offset, 7); +} + +/* Receive ISO transport data packet */ +BOOL iso_recv(HCONN conn) +{ + uint8 code; + + if (!iso_recv_msg(conn, &code) || (code != ISO_PDU_DT)) + { + fprintf(stderr, "ISO error, expected DT\n"); + return False; + } + + return True; +} + +/* Receive ISO transport data packet */ +BOOL iso_send(HCONN conn) +{ + TPKT tpkt; + TPDU tpdu; + + POP_LAYER(conn->out, iso_offset); + iso_make_tpkt(&tpkt, conn->out.end); + iso_io_tpkt(&conn->out, &tpkt); + iso_make_tpdu(&tpdu, ISO_PDU_DT); + iso_io_tpdu(&conn->out, &tpdu); + return tcp_send(conn); +} + +/* Initialise a TPKT structure */ +void iso_make_tpkt(TPKT *tpkt, int length) +{ + tpkt->version = 3; + tpkt->reserved = 0; + tpkt->length = length; +} + +/* Marshall/demarshall a TPKT structure */ +BOOL iso_io_tpkt(STREAM s, TPKT *tpkt) +{ + if (!prs_io_uint8(s, &tpkt->version)) + return False; + + if (tpkt->version != 3) + { + fprintf(stderr, "Wrong TPKT version %d\n", tpkt->version); + return False; + } + + if (!prs_io_uint8 (s, &tpkt->reserved)) + return False; + + if (!msb_io_uint16(s, &tpkt->length)) + return False; + + return True; +} + +/* Initialise a TPDU structure */ +void iso_make_tpdu(TPDU *tpdu, uint8 code) +{ + tpdu->hlen = (code == ISO_PDU_DT) ? 2 : 6; + tpdu->code = code; + tpdu->dst_ref = tpdu->src_ref = 0; + tpdu->class = 0; + tpdu->eot = 0x80; +} + +/* Marshall/demarshall a TPDU structure */ +BOOL iso_io_tpdu(STREAM s, TPDU *tpdu) +{ + BOOL res = True; + + res = res ? prs_io_uint8 (s, &tpdu->hlen) : False; + res = res ? prs_io_uint8 (s, &tpdu->code) : False; + + if (tpdu->code == ISO_PDU_DT) + { + res = res ? prs_io_uint8(s, &tpdu->eot) : False; + } + else + { + res = res ? msb_io_uint16(s, &tpdu->dst_ref) : False; + res = res ? msb_io_uint16(s, &tpdu->src_ref) : False; + res = res ? prs_io_uint8 (s, &tpdu->class ) : False; + } + + return res; +} diff --git a/iso.h b/iso.h new file mode 100644 index 0000000..4695ae6 --- /dev/null +++ b/iso.h @@ -0,0 +1,54 @@ +/* + rdesktop: A Remote Desktop Protocol client. + Protocol services - ISO layer + Copyright (C) Matthew Chapman 1999-2000 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +/* ISO PDU codes */ +enum ISO_PDU_CODE +{ + ISO_PDU_CR = 0xE0, /* Connection Request */ + ISO_PDU_CC = 0xD0, /* Connection Confirm */ + ISO_PDU_DR = 0x80, /* Disconnect Request */ + ISO_PDU_DT = 0xF0, /* Data */ + ISO_PDU_ER = 0x70 /* Error */ +}; + +/* ISO transport encapsulation over TCP (RFC2126) */ +typedef struct _TPKT +{ + uint8 version; + uint8 reserved; + uint16 length; + +} TPKT; + +/* ISO transport protocol PDU (RFC905) */ +typedef struct _TPDU +{ + uint8 hlen; + uint8 code; + + /* CR, CC, DR PDUs */ + uint16 dst_ref; + uint16 src_ref; + uint8 class; + + /* DT PDU */ + uint8 eot; + +} TPDU; diff --git a/mcs.c b/mcs.c new file mode 100644 index 0000000..0a53023 --- /dev/null +++ b/mcs.c @@ -0,0 +1,544 @@ +/* + rdesktop: A Remote Desktop Protocol client. + Protocol services - Multipoint Communications Service + Copyright (C) Matthew Chapman 1999-2000 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" + +/* Establish a connection up to the MCS layer */ +HCONN mcs_connect(char *server) +{ + HCONN conn; + MCS_CONNECT_RESPONSE mcr; + MCS_AUCF aucf; + + if ((conn = iso_connect(server)) == NULL) + return NULL; + + mcs_send_connect_initial(conn); + if (!iso_recv(conn) || !mcs_io_connect_response(&conn->in, &mcr)) + { + fprintf(stderr, "MCS error, expected Connect-Response\n"); + iso_disconnect(conn); + return NULL; + } + + if (mcr.result != 0) + { + fprintf(stderr, "MCS-Connect-Initial failed, result %d\n", + mcr.result); + iso_disconnect(conn); + return NULL; + } + + mcs_send_edrq(conn); + + mcs_send_aurq(conn); + if (!iso_recv(conn) || !mcs_io_aucf(&conn->in, &aucf)) + { + fprintf(stderr, "MCS error, expected AUcf\n"); + mcs_disconnect(conn); + return NULL; + } + + if (aucf.result != 0) + { + fprintf(stderr, "AUrq failed, result %d\n", mcr.result); + mcs_disconnect(conn); + return NULL; + } + + conn->mcs_userid = aucf.userid; + + if (!mcs_join_channel(conn, aucf.userid + 1001) + || !mcs_join_channel(conn, MCS_GLOBAL_CHANNEL)) + { + mcs_disconnect(conn); + return NULL; + } + + return conn; +} + +BOOL mcs_join_channel(HCONN conn, uint16 chanid) +{ + MCS_CJCF cjcf; + + mcs_send_cjrq(conn, chanid); + if (!iso_recv(conn) || !mcs_io_cjcf(&conn->in, &cjcf)) + { + fprintf(stderr, "MCS error, expected CJcf\n"); + return False; + } + + if (cjcf.result != 0) + { + fprintf(stderr, "CJrq failed, result %d\n", cjcf.result); + return False; + } + + return True; +} + +/* Disconnect from the MCS layer */ +void mcs_disconnect(HCONN conn) +{ + /* Not complete */ + iso_disconnect(conn); +} + +/* Send a Connect-Initial message */ +void mcs_send_connect_initial(HCONN conn) +{ + MCS_CONNECT_INITIAL mci; + + iso_init(conn); + mcs_make_connect_initial(&mci); + mcs_io_connect_initial(&conn->out, &mci); + MARK_END(conn->out); + iso_send(conn); +} + +/* Send a EDrq message */ +void mcs_send_edrq(HCONN conn) +{ + MCS_EDRQ edrq; + + iso_init(conn); + edrq.height = edrq.interval = 1; + mcs_io_edrq(&conn->out, &edrq); + MARK_END(conn->out); + iso_send(conn); +} + +/* Send a AUrq message */ +void mcs_send_aurq(HCONN conn) +{ + MCS_AURQ aurq; + + iso_init(conn); + mcs_io_aurq(&conn->out, &aurq); + MARK_END(conn->out); + iso_send(conn); +} + +/* Send a CJrq message */ +void mcs_send_cjrq(HCONN conn, uint16 chanid) +{ + MCS_CJRQ cjrq; + + iso_init(conn); + cjrq.userid = conn->mcs_userid; + cjrq.chanid = chanid; + mcs_io_cjrq(&conn->out, &cjrq); + MARK_END(conn->out); + iso_send(conn); +} + +/* Initialise MCS transport data packet */ +void mcs_init_data(HCONN conn) +{ + iso_init(conn); + PUSH_LAYER(conn->out, mcs_offset, 8); +} + +/* Transmit MCS transport data packet */ +void mcs_send_data(HCONN conn, uint16 chanid, BOOL request) +{ + MCS_DATA dt; + + POP_LAYER(conn->out, mcs_offset); + dt.userid = conn->mcs_userid; + dt.chanid = chanid; + dt.flags = 0x70; + dt.length = conn->out.end - conn->out.offset - 8; + mcs_io_data(&conn->out, &dt, request); + iso_send(conn); +} + +/* Receive a message on the MCS layer */ +BOOL mcs_recv(HCONN conn, BOOL request) +{ + MCS_DATA data; + + return (iso_recv(conn)) && mcs_io_data(&conn->in, &data, request); +} + +/* Initialise a DOMAIN_PARAMS structure */ +void mcs_make_domain_params(DOMAIN_PARAMS *dp, uint16 max_channels, + uint16 max_users, uint16 max_tokens, uint16 max_pdusize) +{ + dp->max_channels = max_channels; + dp->max_users = max_users; + dp->max_tokens = max_tokens; + dp->num_priorities = 1; + dp->min_throughput = 0; + dp->max_height = 1; + dp->max_pdusize = max_pdusize; + dp->ver_protocol = 2; +} + +/* RDP-specific 'user data'. Let's just get this right for now - to be + decoded later. */ +char precanned_connect_userdata[] = { + 0x00,0x05,0x00,0x14,0x7c,0x00,0x01,0x80,0x9e,0x00,0x08,0x00,0x10,0x00, + 0x01,0xc0,0x00,0x44,0x75,0x63,0x61,0x80,0x90,0x01,0xc0,0x88,0x00,0x01, + 0x00,0x08,0x00,0x80,0x02,0xe0,0x01,0x01,0xca,0x03,0xaa,0x09,0x04,0x00, + 0x00,0xa3,0x01,0x00,0x00,0x52,0x00,0x45,0x00,0x53,0x00,0x31,0x00,0x2d, + 0x00,0x4e,0x00,0x45,0x00,0x57,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x01,0xca,0x00,0x00,0x02,0xc0,0x08,0x00,0x00,0x00,0x00,0x00 }; + +/* Initialise a MCS_CONNECT_INITIAL structure */ +void mcs_make_connect_initial(MCS_CONNECT_INITIAL *mci) +{ + mci->calling_domain.length = 0; + mci->calling_domain.data = NULL; + + mci->called_domain.length = 0; + mci->called_domain.data = NULL; + + mci->upward_flag = 0xff; + + mcs_make_domain_params(&mci->target_params, 2, 2, 0, 0xffff); + mcs_make_domain_params(&mci->minimum_params, 1, 1, 1, 0x420); + mcs_make_domain_params(&mci->maximum_params, 0xffff, 0xfc17, 0xffff, + 0xffff); + + mci->user_data.length = sizeof(precanned_connect_userdata); + mci->user_data.data = precanned_connect_userdata; + + mci->length = 2*2 + 3 + 3*34 + 4 + mci->user_data.length; +} + +/* Marshall/demarshall an ASN.1 BER header */ +BOOL ber_io_header(STREAM s, BOOL islong, int tagval, int *length) +{ + uint16 word_tag; + uint8 byte_tag; + uint16 word_len; + uint8 byte_len; + uint8 byte_int; + int tag; + BOOL res; + + /* Read/write tag */ + if (islong) { + word_tag = tagval; + res = msb_io_uint16(s, &word_tag); + tag = word_tag; + } else { + byte_tag = tagval; + res = prs_io_uint8(s, &byte_tag); + tag = byte_tag; + } + + if (!res || (tag != tagval)) { + fprintf(stderr, "Invalid ASN.1 tag\n"); + return False; + } + + /* Read/write length */ + if (s->marshall) + { + if (*length >= 0x80) + { + byte_len = 0x82; + word_len = (uint16)*length; + res = prs_io_uint8(s, &byte_len); + res = res ? msb_io_uint16(s, &word_len) : False; + } + else + { + byte_len = (uint8)*length; + res = prs_io_uint8(s, &byte_len); + } + } + else + { + if (!prs_io_uint8(s, &byte_len)) + return False; + + if (byte_len & 0x80) + { + byte_len &= ~0x80; + *length = 0; + while (byte_len--) + { + if (!prs_io_uint8(s, &byte_int)) + return False; + + *length <<= 8; + *length += byte_int; + } + } + else *length = byte_len; + } + + return res; +} + +/* Marshall/demarshall an octet string (ASN.1 BER) */ +BOOL ber_io_octet_string(STREAM s, OCTET_STRING *os) +{ + if (!ber_io_header(s, False, 4, &os->length)) + return False; + + if (os->length > s->end - s->offset) + return False; + + if (s->marshall) + { + memcpy(s->data + s->offset, os->data, os->length); + } + else + { + os->data = malloc(os->length); + memcpy(os->data, s->data + s->offset, os->length); + } + + s->offset += os->length; + return True; +} + +/* Marshall/demarshall an integer (ASN.1 BER) */ +BOOL ber_io_integer(STREAM s, uint16 *word_int) +{ + int length = 2; + uint8 byte_int; + BOOL res; + + if (!ber_io_header(s, False, 2, &length)) + return False; + + if (s->marshall) + { + res = msb_io_uint16(s, word_int); + } + else + { + *word_int = 0; + while (length--) + { + if (!prs_io_uint8(s, &byte_int)) + return False; + + *word_int <<= 8; + *word_int += byte_int; + } + } + + return res; +} + +/* Marshall/demarshall a simple uint8 type (ASN.1 BER) */ +BOOL ber_io_uint8(STREAM s, uint8 *i, int tagval) +{ + int length = 1; + + if (!ber_io_header(s, False, tagval, &length)) + return False; + + if (length != 1) + { + fprintf(stderr, "Wrong length for simple type\n"); + return False; + } + + return prs_io_uint8(s, i); +} + +/* Marshall/demarshall a DOMAIN_PARAMS structure (ASN.1 BER) */ +BOOL mcs_io_domain_params(STREAM s, DOMAIN_PARAMS *dp) +{ + int length = 32; + BOOL res; + + res = ber_io_header(s, False, 0x30, &length); + res = res ? ber_io_integer(s, &dp->max_channels ) : False; + res = res ? ber_io_integer(s, &dp->max_users ) : False; + res = res ? ber_io_integer(s, &dp->max_tokens ) : False; + res = res ? ber_io_integer(s, &dp->num_priorities) : False; + res = res ? ber_io_integer(s, &dp->min_throughput) : False; + res = res ? ber_io_integer(s, &dp->max_height ) : False; + res = res ? ber_io_integer(s, &dp->max_pdusize ) : False; + res = res ? ber_io_integer(s, &dp->ver_protocol ) : False; + + return res; +} + +/* Marshall/demarshall a MCS_CONNECT_INITIAL structure (ASN.1 BER) */ +BOOL mcs_io_connect_initial(STREAM s, MCS_CONNECT_INITIAL *mci) +{ + BOOL res; + + res = ber_io_header(s, True, 0x7f65, &mci->length); + res = res ? ber_io_octet_string (s, &mci->calling_domain) : False; + res = res ? ber_io_octet_string (s, &mci->called_domain ) : False; + res = res ? ber_io_uint8 (s, &mci->upward_flag, 1) : False; + res = res ? mcs_io_domain_params(s, &mci->target_params ) : False; + res = res ? mcs_io_domain_params(s, &mci->minimum_params) : False; + res = res ? mcs_io_domain_params(s, &mci->maximum_params) : False; + res = res ? ber_io_octet_string (s, &mci->user_data ) : False; + + return res; +} + +/* Marshall/demarshall a MCS_CONNECT_RESPONSE structure (ASN.1 BER) */ +BOOL mcs_io_connect_response(STREAM s, MCS_CONNECT_RESPONSE *mcr) +{ + BOOL res; + + res = ber_io_header(s, True, 0x7f66, &mcr->length); + res = res ? ber_io_uint8 (s, &mcr->result, 10 ) : False; + res = res ? ber_io_integer (s, &mcr->connect_id ) : False; + res = res ? mcs_io_domain_params(s, &mcr->domain_params) : False; + res = res ? ber_io_octet_string (s, &mcr->user_data ) : False; + + return res; +} + +/* Marshall/demarshall an EDrq structure (ASN.1 PER) */ +BOOL mcs_io_edrq(STREAM s, MCS_EDRQ *edrq) +{ + uint8 opcode = (1) << 2; + uint8 pkt_opcode = opcode; + BOOL res; + + res = prs_io_uint8(s, &pkt_opcode); + if (pkt_opcode != opcode) + { + fprintf(stderr, "Expected EDrq, received %x\n", pkt_opcode); + return False; + } + + res = res ? msb_io_uint16(s, &edrq->height ) : False; + res = res ? msb_io_uint16(s, &edrq->interval) : False; + + return res; +} + +/* Marshall/demarshall an AUrq structure (ASN.1 PER) */ +BOOL mcs_io_aurq(STREAM s, MCS_AURQ *aurq) +{ + uint8 opcode = (10) << 2; + uint8 pkt_opcode = opcode; + BOOL res; + + res = prs_io_uint8(s, &pkt_opcode); + if (pkt_opcode != opcode) + { + fprintf(stderr, "Expected AUrq, received %x\n", pkt_opcode); + return False; + } + + return res; +} + +/* Marshall/demarshall an AUcf structure (ASN.1 PER) */ +BOOL mcs_io_aucf(STREAM s, MCS_AUCF *aucf) +{ + uint8 opcode = (11) << 2; + uint8 pkt_opcode = opcode | 2; + BOOL res; + + res = prs_io_uint8(s, &pkt_opcode); + if ((pkt_opcode & 0xfc) != opcode) + { + fprintf(stderr, "Expected AUcf, received %x\n", pkt_opcode); + return False; + } + + res = res ? prs_io_uint8 (s, &aucf->result) : False; + if (pkt_opcode & 2) + res = res ? msb_io_uint16(s, &aucf->userid) : False; + + return res; +} + +/* Marshall/demarshall an CJrq structure (ASN.1 PER) */ +BOOL mcs_io_cjrq(STREAM s, MCS_CJRQ *cjrq) +{ + uint8 opcode = (14) << 2; + uint8 pkt_opcode = opcode; + BOOL res; + + res = prs_io_uint8(s, &pkt_opcode); + if (pkt_opcode != opcode) + { + fprintf(stderr, "Expected CJrq, received %x\n", pkt_opcode); + return False; + } + + res = res ? msb_io_uint16(s, &cjrq->userid) : False; + res = res ? msb_io_uint16(s, &cjrq->chanid) : False; + + return res; +} + +/* Marshall/demarshall an CJcf structure (ASN.1 PER) */ +BOOL mcs_io_cjcf(STREAM s, MCS_CJCF *cjcf) +{ + uint8 opcode = (15) << 2; + uint8 pkt_opcode = opcode | 2; + BOOL res; + + res = prs_io_uint8(s, &pkt_opcode); + if ((pkt_opcode & 0xfc) != opcode) + { + fprintf(stderr, "Expected CJcf, received %x\n", pkt_opcode); + return False; + } + + res = res ? prs_io_uint8 (s, &cjcf->result) : False; + res = res ? msb_io_uint16(s, &cjcf->userid) : False; + res = res ? msb_io_uint16(s, &cjcf->req_chanid) : False; + if (pkt_opcode & 2) + res = res ? msb_io_uint16(s, &cjcf->join_chanid) : False; + + return res; +} + +/* Marshall/demarshall an SDrq or SDin packet (ASN.1 PER) */ +BOOL mcs_io_data(STREAM s, MCS_DATA *dt, BOOL request) +{ + uint8 opcode = (request ? 25 : 26) << 2; + uint8 pkt_opcode = opcode; + BOOL res; + + res = prs_io_uint8(s, &pkt_opcode); + if (pkt_opcode != opcode) + { + fprintf(stderr, "Expected MCS data, received %x\n", pkt_opcode); + return False; + } + + dt->length |= 0x8000; + + res = res ? msb_io_uint16(s, &dt->userid) : False; + res = res ? msb_io_uint16(s, &dt->chanid) : False; + res = res ? prs_io_uint8 (s, &dt->flags ) : False; + res = res ? msb_io_uint16(s, &dt->length) : False; + + return res; +} diff --git a/mcs.h b/mcs.h new file mode 100644 index 0000000..ef18a5d --- /dev/null +++ b/mcs.h @@ -0,0 +1,120 @@ +/* + rdesktop: A Remote Desktop Protocol client. + Protocol services - Multipoint Communications Service + Copyright (C) Matthew Chapman 1999-2000 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +/* An ASN.1 octet string */ +typedef struct _OCTET_STRING +{ + int length; + unsigned char *data; + +} OCTET_STRING; + +/* MCS domain parameters */ +typedef struct _DOMAIN_PARAMS +{ + uint16 max_channels; + uint16 max_users; + uint16 max_tokens; + uint16 num_priorities; + uint16 min_throughput; + uint16 max_height; + uint16 max_pdusize; + uint16 ver_protocol; + +} DOMAIN_PARAMS; + +/* MCS-CONNECT-INITIAL request */ +typedef struct _MCS_CONNECT_INITIAL +{ + int length; + + OCTET_STRING calling_domain; + OCTET_STRING called_domain; + uint8 upward_flag; + DOMAIN_PARAMS target_params; + DOMAIN_PARAMS minimum_params; + DOMAIN_PARAMS maximum_params; + OCTET_STRING user_data; + +} MCS_CONNECT_INITIAL; + +/* MCS-CONNECT-RESPONSE */ +typedef struct _MCS_CONNECT_RESPONSE +{ + int length; + + uint8 result; + uint16 connect_id; + DOMAIN_PARAMS domain_params; + OCTET_STRING user_data; + +} MCS_CONNECT_RESPONSE; + +/* EDrq - Erect Domain Request */ +typedef struct _MCS_EDRQ +{ + uint16 height; + uint16 interval; + +} MCS_EDRQ; + +/* AUrq - Attach User Request */ +typedef struct _MCS_AURQ +{ + +} MCS_AURQ; + +/* AUcf - Attach User Confirm */ +typedef struct _MCS_AUCF +{ + uint8 result; + uint16 userid; + +} MCS_AUCF; + +/* CJrq - Channel Join Request */ +typedef struct _MCS_CJRQ +{ + uint16 userid; + uint16 chanid; + +} MCS_CJRQ; + +/* CJcf - Channel Join Confirm */ +typedef struct _MCS_CJCF +{ + uint8 result; + uint16 userid; + uint16 req_chanid; + uint16 join_chanid; + +} MCS_CJCF; + +/* SDrq/SDin - Send Data */ +typedef struct _MCS_DATA +{ + uint16 userid; + uint16 chanid; + uint8 flags; + uint16 length; + +} MCS_DATA; + +#define MCS_GLOBAL_CHANNEL 1003 diff --git a/parse.c b/parse.c new file mode 100644 index 0000000..c326f09 --- /dev/null +++ b/parse.c @@ -0,0 +1,126 @@ +/* + rdesktop: A Remote Desktop Protocol client. + Protocol services - parsing layer + Copyright (C) Matthew Chapman 1999-2000 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" + +/* Parse a 8-bit integer */ +BOOL prs_io_uint8(STREAM s, uint8 *i) +{ + if (s->offset + 1 > s->end) + { + fprintf(stderr, "Parse past end of buffer\n"); + return False; + } + + if (s->marshall) + s->data[s->offset] = *i; + else + *i = s->data[s->offset]; + + s->offset++; + return True; +} + +/* Parse a sequence of 8-bit integers */ +BOOL prs_io_uint8s(STREAM s, uint8 *p, unsigned int length) +{ + if (s->offset + length > s->end) + { + fprintf(stderr, "Parse past end of buffer\n"); + return False; + } + + if (s->marshall) + memcpy(s->data + s->offset, p, length); + else + memcpy(p, s->data + s->offset, length); + + s->offset += length; + return True; +} + +/* Parse a 16-bit integer, most significant bytes first */ +BOOL msb_io_uint16(STREAM s, uint16 *i) +{ + int offset = s->offset; + + if (offset + 2 > s->end) + { + fprintf(stderr, "Parse past end of buffer\n"); + return False; + } + + if (s->marshall) { + s->data[offset] = (uint8)(*i >> 8); + s->data[offset+1] = (uint8)(*i); + } else { + *i = (s->data[offset] << 8) + (s->data[offset+1]); + } + + s->offset+=2; + return True; +} + +/* Parse a 16-bit integer, least significant bytes first */ +BOOL lsb_io_uint16(STREAM s, uint16 *i) +{ + int offset = s->offset; + + if (offset + 2 > s->end) + { + fprintf(stderr, "Parse past end of buffer\n"); + return False; + } + + if (s->marshall) { + s->data[offset] = (uint8)(*i); + s->data[offset+1] = (uint8)(*i >> 8); + } else { + *i = (s->data[offset]) + (s->data[offset+1] << 8); + } + + s->offset += 2; + return True; +} + +/* Parse a 32-bit integer, least significant bytes first */ +BOOL lsb_io_uint32(STREAM s, uint32 *i) +{ + int offset = s->offset; + + if (offset + 4 > s->end) + { + fprintf(stderr, "Parse past end of buffer\n"); + return False; + } + + if (s->marshall) { + s->data[offset] = (uint8)(*i); + s->data[offset+1] = (uint8)(*i >> 8); + s->data[offset+2] = (uint8)(*i >> 16); + s->data[offset+3] = (uint8)(*i >> 24); + } else { + *i = (s->data[offset]) + (s->data[offset+1] << 8) + + (s->data[offset+2] << 16) + (s->data[offset+3] << 24); + } + + s->offset += 4; + return True; +} diff --git a/parse.h b/parse.h new file mode 100644 index 0000000..f318bc6 --- /dev/null +++ b/parse.h @@ -0,0 +1,59 @@ +/* + rdesktop: A Remote Desktop Protocol client. + Protocol services - parsing layer + Copyright (C) Matthew Chapman 1999-2000 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +/* Parser state */ +typedef struct stream +{ + /* Parsing layer */ + unsigned char *data; + unsigned int size; + unsigned int offset; + unsigned int end; + BOOL marshall; + BOOL error; + + /* Other layers */ + int iso_offset; + int mcs_offset; + int rdp_offset; + +} *STREAM; + +/* Connection state */ +typedef struct connection +{ + /* Parsing layer */ + struct stream in; + struct stream out; + + /* TCP layer */ + int tcp_socket; + + /* MCS layer */ + uint16 mcs_userid; + +} *HCONN; + +#define STREAM_INIT(s,m) { s.data = xmalloc(2048); s.end = s.size = 2048; s.offset = 0; s.marshall = m; s.error = False; } +#define STREAM_SIZE(s,l) { if (l > s.size) { s.data = xrealloc(s.data,l); s.end = s.size = l; } } +#define REMAINING(s) ( s->end - s->offset ) +#define PUSH_LAYER(s,v,l) { s.v = s.offset; s.offset += l; } +#define POP_LAYER(s,v) { s.offset = s.v; } +#define MARK_END(s) { s.end = s.offset; } diff --git a/proto.h b/proto.h new file mode 100644 index 0000000..bc0dd8e --- /dev/null +++ b/proto.h @@ -0,0 +1,133 @@ +/* + rdesktop: A Remote Desktop Protocol client. + Function prototypes + Copyright (C) Matthew Chapman 1999-2000 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +/* Parsing layer */ +BOOL prs_io_uint8(STREAM s, uint8 *i); +BOOL prs_io_uint8s(STREAM s, uint8 *p, unsigned int length); +BOOL msb_io_uint16(STREAM s, uint16 *i); +BOOL lsb_io_uint16(STREAM s, uint16 *i); +BOOL lsb_io_uint32(STREAM s, uint32 *i); + +/* TCP layer */ +HCONN tcp_connect(char *server); +void tcp_disconnect(HCONN conn); +BOOL tcp_send(HCONN conn); +BOOL tcp_recv(HCONN conn, int length); + +/* ISO layer */ +HCONN iso_connect(char *server); +void iso_disconnect(HCONN conn); +BOOL iso_send_msg(HCONN conn, uint8 code); +BOOL iso_recv_msg(HCONN conn, uint8 *code); +void iso_init(struct connection *conn); +BOOL iso_send(HCONN conn); +BOOL iso_recv(HCONN conn); +void iso_make_tpkt(TPKT *tpkt, int length); +BOOL iso_io_tpkt(STREAM s, TPKT *tpkt); +void iso_make_tpdu(TPDU *tpdu, uint8 code); +BOOL iso_io_tpdu(STREAM s, TPDU *tpdu); + +/* MCS layer */ +HCONN mcs_connect(char *server); +BOOL mcs_join_channel(HCONN conn, uint16 chanid); +void mcs_disconnect(HCONN conn); +void mcs_send_connect_initial(HCONN conn); +void mcs_send_edrq(HCONN conn); +void mcs_send_aurq(HCONN conn); +void mcs_send_cjrq(HCONN conn, uint16 chanid); +void mcs_init_data(HCONN conn); +void mcs_send_data(HCONN conn, uint16 chanid, BOOL request); +int mcs_recv(HCONN conn, BOOL request); +void mcs_make_domain_params(DOMAIN_PARAMS *dp, uint16 max_channels, + uint16 max_users, uint16 max_tokens, uint16 max_pdusize); +void mcs_make_connect_initial(MCS_CONNECT_INITIAL *mci); +BOOL ber_io_header(STREAM s, BOOL islong, int tagval, int *length); +BOOL ber_io_octet_string(STREAM s, OCTET_STRING *os); +BOOL ber_io_integer(STREAM s, uint16 *i); +BOOL ber_io_uint8(STREAM s, uint8 *i, int tagval); +BOOL mcs_io_domain_params(STREAM s, DOMAIN_PARAMS *dp); +BOOL mcs_io_connect_initial(STREAM s, MCS_CONNECT_INITIAL *mci); +BOOL mcs_io_connect_response(STREAM s, MCS_CONNECT_RESPONSE *mcr); +BOOL mcs_io_edrq(STREAM s, MCS_EDRQ *edrq); +BOOL mcs_io_aurq(STREAM s, MCS_AURQ *aurq); +BOOL mcs_io_aucf(STREAM s, MCS_AUCF *aucf); +BOOL mcs_io_cjrq(STREAM s, MCS_CJRQ *cjrq); +BOOL mcs_io_cjcf(STREAM s, MCS_CJCF *cjcf); +BOOL mcs_io_data(STREAM s, MCS_DATA *dt, BOOL request); + +/* RDP layer */ +HCONN rdp_connect(char *server); +void process_orders(HCONN conn, RDP_ORDER_STATE *os); +void rdp_establish_key(HCONN conn); +void rdp_send_cert(HCONN conn); +void rdp_send_confirm_active(HCONN conn); +void rdp_send_control(HCONN conn, uint16 action); +void rdp_send_synchronize(HCONN conn); +void rdp_send_fonts(HCONN conn, uint16 seqno); +void rdp_send_input(HCONN conn); +BOOL rdp_recv_pdu(HCONN conn, uint8 *type); +void rdp_disconnect(HCONN conn); +void rdp_make_header(RDP_HEADER *hdr, uint16 length, uint16 pdu_type, + uint16 userid); +void rdp_make_data_header(RDP_DATA_HEADER *hdr, uint32 shareid, + uint16 length, uint16 data_pdu_type); +void rdp_make_general_caps(RDP_GENERAL_CAPS *caps); +void rdp_make_bitmap_caps(RDP_BITMAP_CAPS *caps); +void rdp_make_order_caps(RDP_ORDER_CAPS *caps); +void rdp_make_bmpcache_caps(RDP_BMPCACHE_CAPS *caps); +void rdp_make_control_caps(RDP_CONTROL_CAPS *caps); +void rdp_make_activate_caps(RDP_ACTIVATE_CAPS *caps); +void rdp_make_pointer_caps(RDP_POINTER_CAPS *caps); +void rdp_make_share_caps(RDP_SHARE_CAPS *caps, uint16 userid); +void rdp_make_colcache_caps(RDP_COLCACHE_CAPS *caps); +void rdp_make_active_pdu(RDP_ACTIVE_PDU *pdu, uint32 shareid, uint16 userid); +void rdp_make_control_pdu(RDP_CONTROL_PDU *pdu, uint16 action); +void rdp_make_synchronize_pdu(RDP_SYNCHRONIZE_PDU *pdu, uint16 userid); +void rdp_make_font_pdu(RDP_FONT_PDU *pdu, uint16 seqno); +void rdp_make_input_pdu(RDP_INPUT_PDU *pdu); +BOOL rdp_io_header(STREAM s, RDP_HEADER *hdr); +BOOL rdp_io_data_header(STREAM s, RDP_DATA_HEADER *hdr); +BOOL rdp_io_general_caps(STREAM s, RDP_GENERAL_CAPS *caps); +BOOL rdp_io_bitmap_caps(STREAM s, RDP_BITMAP_CAPS *caps); +BOOL rdp_io_order_caps(STREAM s, RDP_ORDER_CAPS *caps); +BOOL rdp_io_bmpcache_info(STREAM s, RDP_BMPCACHE_INFO *info); +BOOL rdp_io_bmpcache_caps(STREAM s, RDP_BMPCACHE_CAPS *caps); +BOOL rdp_io_control_caps(STREAM s, RDP_CONTROL_CAPS *caps); +BOOL rdp_io_activate_caps(STREAM s, RDP_ACTIVATE_CAPS *caps); +BOOL rdp_io_pointer_caps(STREAM s, RDP_POINTER_CAPS *caps); +BOOL rdp_io_share_caps(STREAM s, RDP_SHARE_CAPS *caps); +BOOL rdp_io_colcache_caps(STREAM s, RDP_COLCACHE_CAPS *caps); +BOOL rdp_io_active_pdu(STREAM s, RDP_ACTIVE_PDU *pdu, int pdutype); +BOOL rdp_io_control_pdu(STREAM s, RDP_CONTROL_PDU *pdu); +BOOL rdp_io_synchronize_pdu(STREAM s, RDP_SYNCHRONIZE_PDU *pdu); +BOOL rdp_io_input_event(STREAM s, RDP_INPUT_EVENT *evt); +BOOL rdp_io_input_pdu(STREAM s, RDP_INPUT_PDU *pdu); +BOOL rdp_io_font_info(STREAM s, RDP_FONT_INFO *font); +BOOL rdp_io_font_pdu(STREAM s, RDP_FONT_PDU *pdu); +BOOL rdp_io_update_pdu(STREAM s, RDP_UPDATE_PDU *pdu); +BOOL rdp_io_secondary_order(STREAM s, RDP_SECONDARY_ORDER *rso); +BOOL rdp_io_bitmap_header(STREAM s, RDP_BITMAP_HEADER *rdh); + +/* Utility routines */ +void *xmalloc(int size); +void *xrealloc(void *oldmem, int size); +BOOL bitmap_decompress(unsigned char *input, int size, + unsigned char *output, int width); + diff --git a/rdp.c b/rdp.c new file mode 100644 index 0000000..8d56b12 --- /dev/null +++ b/rdp.c @@ -0,0 +1,1135 @@ +/* + rdesktop: A Remote Desktop Protocol client. + Protocol services - RDP layer + Copyright (C) Matthew Chapman 1999-2000 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" + +/* Establish a connection up to the RDP layer */ +HCONN rdp_connect(char *server) +{ + HCONN conn; + RDP_ACTIVE_PDU active; + RDP_DATA_HEADER hdr; + RDP_UPDATE_PDU update; + RDP_ORDER_STATE os; + uint8 type; + + memset(&os, 0, sizeof(os)); + + if ((conn = mcs_connect(server)) == NULL) + return NULL; + + rdp_establish_key(conn); + mcs_recv(conn, False); /* Server's licensing certificate */ + rdp_send_cert(conn); + mcs_recv(conn, False); + + if (rdp_recv_pdu(conn, &type) && (type != RDP_PDU_DEMAND_ACTIVE)) + { + fprintf(stderr, "RDP error, expected Demand Active\n"); + mcs_disconnect(conn); + return NULL; + } + + rdp_io_active_pdu(&conn->in, &active, RDP_PDU_DEMAND_ACTIVE); + rdp_send_confirm_active(conn); + rdp_send_synchronize(conn); + rdp_send_control(conn, RDP_CTL_COOPERATE); + rdp_send_control(conn, RDP_CTL_REQUEST_CONTROL); + rdp_recv_pdu(conn, &type); // RDP_PDU_SYNCHRONIZE + rdp_recv_pdu(conn, &type); // RDP_CTL_COOPERATE + rdp_recv_pdu(conn, &type); // RDP_CTL_GRANT_CONTROL + rdp_send_input(conn); + rdp_send_fonts(conn, 1); + rdp_send_fonts(conn, 2); + rdp_recv_pdu(conn, &type); // RDP_PDU_UNKNOWN 0x28 + while (rdp_recv_pdu(conn, &type)) + { + if (type != RDP_PDU_DATA) + continue; + + rdp_io_data_header(&conn->in, &hdr); + + switch (hdr.data_pdu_type) + { + case RDP_DATA_PDU_UPDATE: + rdp_io_update_pdu(&conn->in, &update); + if (update.update_type == RDP_UPDATE_ORDERS) + { + fprintf(stderr, "Received orders\n"); + process_orders(conn, &os); + } + break; + } + } + + return conn; +} + +void prs_io_coord(STREAM s, uint16 *coord, BOOL delta) +{ + uint8 change; + + if (delta) + { + prs_io_uint8(s, &change); + *coord += change; + } + else + { + lsb_io_uint16(s, coord); + } +} + +void process_opaque_rect(HCONN conn, RDP_ORDER_STATE *os, BOOL delta) +{ + uint8 present; + prs_io_uint8(&conn->in, &present); + + if (present & 1) + prs_io_coord(&conn->in, &os->opaque_rect.x, delta); + + if (present & 2) + prs_io_coord(&conn->in, &os->opaque_rect.y, delta); + + if (present & 4) + prs_io_coord(&conn->in, &os->opaque_rect.cx, delta); + + if (present & 8) + prs_io_coord(&conn->in, &os->opaque_rect.cy, delta); + + if (present & 16) + prs_io_uint8(&conn->in, &os->opaque_rect.colour); + + fprintf(stderr, "Opaque rectangle at %d, %d\n", os->opaque_rect.x, os->opaque_rect.y); +} + +void process_orders(HCONN conn, RDP_ORDER_STATE *os) +{ + uint16 num_orders; + int processed = 0; + BOOL res = True; + // unsigned char *p; + + lsb_io_uint16(&conn->in, &num_orders); + + conn->in.offset += 2; + // p = &conn->in.data[conn->in.offset]; + + // fprintf(stderr, "%02X %02X %02X %02X\n", p[0], p[1], p[2], p[3]); + + while ((processed < num_orders) && res) + { + uint8 order_flags; + + prs_io_uint8(&conn->in, &order_flags); + + if (!(order_flags & RDP_ORDER_STANDARD)) + return; + + if (order_flags & RDP_ORDER_SECONDARY) + { + RDP_SECONDARY_ORDER rso; + + rdp_io_secondary_order(&conn->in, &rso); + switch (rso.type) + { + case RDP_ORDER_BMPCACHE: + { + RDP_BITMAP_HEADER rbh; + char output[8192]; + + rdp_io_bitmap_header(&conn->in, &rbh); + fprintf(stderr, "Decompressing bitmap %d x %d, final size %d\n", rbh.width, rbh.height, rbh.final_size); + bitmap_decompress(conn->in.data + + conn->in.offset, rbh.size, + output, rbh.width); + conn->in.offset += rbh.size; + break; + } + default: + fprintf(stderr, "Unknown secondary order %d\n", + rso.type); + return; + } + + + } + + if (order_flags & RDP_ORDER_CHANGE) + prs_io_uint8(&conn->in, &os->order_type); + + switch (os->order_type) + { + case RDP_ORDER_OPAQUE_RECT: + process_opaque_rect(conn, os, order_flags & RDP_ORDER_DELTA); + break; + default: + fprintf(stderr, "Unknown order %d\n", os->order_type); + return; + } + + processed++; + } +} + +/* Work this out later. This is useless anyway when encryption is off. */ +uint8 precanned_key_packet[] = { + 0x48,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x6c,0x86, + 0xf7,0x99,0xef,0x60,0xc4,0x49,0x52,0xd0,0xd8,0xea,0xb5,0x4f,0x58,0x19, + 0x52,0x2a,0x93,0x83,0x57,0x4f,0x4e,0x04,0xde,0x96,0x51,0xab,0x13,0x20, + 0xd8,0xe5,0x00,0x00,0x00,0x00,0x00,0x00 +}; + +/* Create an RC4 key and transfer it to the server */ +void rdp_establish_key(HCONN conn) +{ + mcs_init_data(conn); + memcpy(conn->out.data + conn->out.offset, precanned_key_packet, + sizeof(precanned_key_packet)); + conn->out.offset += sizeof(precanned_key_packet); + MARK_END(conn->out); + mcs_send_data(conn, MCS_GLOBAL_CHANNEL, True); +} + +/* Horrible horrible certificate stuff. Work out later. */ +uint8 precanned_cert_packet[] = { +0x80,0x00,0x00,0x00,0x12,0x02,0xb4,0x04,0x01,0x00,0x00, +0x00,0x00,0x00,0x01,0x02,0x9d,0xa3,0x7a,0x93,0x34,0x7b,0x28,0x37,0x24,0xa0,0x1f, +0x61,0x26,0xfd,0x96,0x3a,0x92,0x83,0xf3,0xe9,0x6a,0x2e,0x81,0x7c,0x2c,0xe4,0x72,// +0x01,0x18,0xe9,0xa1,0x0f,0x00,0x00,0x48,0x00,0x84,0x23,0x90,0xe6,0xd3,0xf8,0x20, +0xdb,0xa8,0x1b,0xb2,0xd0,0x78,0x2c,0x35,0xde,0xe3,0x0e,0x63,0x40,0xca,0xac,0x71, +0xc9,0x17,0x49,0x05,0x25,0xeb,0x9b,0xd0,0xa6,0x5c,0x90,0x3e,0x9d,0x4b,0x27,0x01, +0x79,0x1c,0x22,0xfb,0x3c,0x2c,0xb9,0x9f,0xf5,0x21,0xf3,0xee,0xd5,0x4d,0x47,0x1c, +0x85,0xbe,0x83,0x93,0xe8,0xed,0x8c,0x5c,0x82,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x01,0x00,0x10,0x04,0x30,0x82,0x04,0x0c,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7, +0x0d,0x01,0x07,0x02,0xa0,0x82,0x03,0xfd,0x30,0x82,0x03,0xf9,0x02,0x01,0x01,0x31, +0x00,0x30,0x0b,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x07,0x01,0xa0,0x82, +0x03,0xe1,0x30,0x82,0x01,0x77,0x30,0x82,0x01,0x25,0xa0,0x03,0x02,0x01,0x02,0x02, +0x08,0x01,0xbf,0x06,0x84,0x9d,0xdb,0x2d,0xe0,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48, +0x86,0xf7,0x0d,0x01,0x01,0x01,0x05,0x00,0x30,0x38,0x31,0x36,0x30,0x11,0x06,0x03, +0x55,0x04,0x03,0x1e,0x0a,0x00,0x4e,0x00,0x54,0x00,0x54,0x00,0x53,0x00,0x45,0x30, +0x21,0x06,0x03,0x55,0x04,0x07,0x1e,0x1a,0x00,0x4d,0x00,0x69,0x00,0x63,0x00,0x72, +0x00,0x6f,0x00,0x73,0x00,0x6f,0x00,0x66,0x00,0x74,0x00,0x2e,0x00,0x63,0x00,0x6f, +0x00,0x6d,0x30,0x1e,0x17,0x0d,0x39,0x39,0x30,0x39,0x32,0x34,0x31,0x32,0x30,0x32, +0x30,0x34,0x5a,0x17,0x0d,0x34,0x39,0x30,0x39,0x32,0x34,0x31,0x32,0x30,0x32,0x30, +0x34,0x5a,0x30,0x38,0x31,0x36,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x1e,0x0a,0x00, +0x4e,0x00,0x54,0x00,0x54,0x00,0x53,0x00,0x45,0x30,0x21,0x06,0x03,0x55,0x04,0x07, +0x1e,0x1a,0x00,0x4d,0x00,0x69,0x00,0x63,0x00,0x72,0x00,0x6f,0x00,0x73,0x00,0x6f, +0x00,0x66,0x00,0x74,0x00,0x2e,0x00,0x63,0x00,0x6f,0x00,0x6d,0x30,0x5c,0x30,0x0d, +0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x01,0x05,0x00,0x03,0x4b,0x00, +0x30,0x48,0x02,0x41,0x00,0x91,0xb2,0x16,0x1c,0xae,0x4f,0x7f,0x7c,0xaf,0x57,0x2b, +0x23,0x4c,0x0c,0x25,0x3c,0x4f,0x66,0x9d,0x25,0xc3,0x4f,0x29,0xee,0x8b,0xda,0x4e, +0x95,0xe7,0x3b,0xaa,0xc0,0xa7,0xba,0xaf,0x99,0x8c,0x47,0x24,0x8b,0x09,0x77,0xbc, +0x2c,0xf4,0xe7,0x1a,0x07,0x58,0x7b,0x11,0x37,0x2a,0xa8,0x90,0xc3,0x50,0x92,0x80, +0x15,0xc5,0xda,0x51,0x8b,0x02,0x03,0x01,0x00,0x01,0xa3,0x13,0x30,0x11,0x30,0x0f, +0x06,0x03,0x55,0x1d,0x13,0x04,0x08,0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x00,0x30, +0x09,0x06,0x05,0x2b,0x0e,0x03,0x02,0x1d,0x05,0x00,0x03,0x41,0x00,0x14,0x04,0x67, +0x28,0xc8,0xd3,0x1f,0x13,0x14,0x2e,0x2c,0x93,0x09,0x25,0xbb,0xbe,0x86,0x6a,0xd3, +0x47,0x6f,0x44,0x16,0x7b,0x94,0x8c,0xb2,0xa2,0xd5,0xf7,0x4f,0xb1,0x8f,0x7f,0xde, +0x0b,0x88,0x34,0x4a,0x1d,0xdc,0xa1,0xfd,0x26,0xbd,0x43,0xbb,0x38,0xf1,0x87,0x34, +0xbb,0xe9,0x3b,0xfa,0x7f,0x1e,0xff,0xe1,0x10,0x7e,0xee,0x6e,0xd8,0x30,0x82,0x02, +0x62,0x30,0x82,0x02,0x10,0xa0,0x03,0x02,0x01,0x02,0x02,0x05,0x01,0x00,0x00,0x00, +0x01,0x30,0x09,0x06,0x05,0x2b,0x0e,0x03,0x02,0x1d,0x05,0x00,0x30,0x38,0x31,0x36, +0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x1e,0x0a,0x00,0x4e,0x00,0x54,0x00,0x54,0x00, +0x53,0x00,0x45,0x30,0x21,0x06,0x03,0x55,0x04,0x07,0x1e,0x1a,0x00,0x4d,0x00,0x69, +0x00,0x63,0x00,0x72,0x00,0x6f,0x00,0x73,0x00,0x6f,0x00,0x66,0x00,0x74,0x00,0x2e, +0x00,0x63,0x00,0x6f,0x00,0x6d,0x30,0x1e,0x17,0x0d,0x39,0x39,0x30,0x39,0x32,0x34, +0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x17,0x0d,0x34,0x39,0x30,0x39,0x32,0x34,0x30, +0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x79,0x31,0x77,0x30,0x17,0x06,0x03,0x55,0x04, +0x03,0x1e,0x10,0x00,0x52,0x00,0x45,0x00,0x53,0x00,0x37,0x00,0x2d,0x00,0x4e,0x00, +0x45,0x00,0x57,0x30,0x17,0x06,0x03,0x55,0x04,0x07,0x1e,0x10,0x00,0x7a,0x00,0x32, +0x00,0x32,0x00,0x33,0x00,0x32,0x00,0x32,0x00,0x30,0x00,0x33,0x30,0x43,0x06,0x03, +0x55,0x04,0x05,0x1e,0x3c,0x00,0x31,0x00,0x42,0x00,0x63,0x00,0x4b,0x00,0x65,0x00, +0x57,0x00,0x50,0x00,0x6c,0x00,0x37,0x00,0x58,0x00,0x47,0x00,0x61,0x00,0x73,0x00, +0x38,0x00,0x4a,0x00,0x79,0x00,0x50,0x00,0x34,0x00,0x30,0x00,0x7a,0x00,0x49,0x00, +0x6d,0x00,0x6e,0x00,0x6f,0x00,0x51,0x00,0x5a,0x00,0x59,0x00,0x3d,0x00,0x0d,0x00, +0x0a,0x30,0x5c,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x01, +0x05,0x00,0x03,0x4b,0x00,0x30,0x48,0x02,0x41,0x00,0x91,0xb2,0x16,0x1c,0xae,0x4f, +0x7f,0x7c,0xaf,0x57,0x2b,0x23,0x4c,0x0c,0x25,0x3c,0x4f,0x66,0x9d,0x25,0xc3,0x4f, +0x29,0xee,0x8b,0xda,0x4e,0x95,0xe7,0x3b,0xaa,0xc0,0xa7,0xba,0xaf,0x99,0x8c,0x47, +0x24,0x8b,0x09,0x77,0xbc,0x2c,0xf4,0xe7,0x1a,0x07,0x58,0x7b,0x11,0x37,0x2a,0xa8, +0x90,0xc3,0x50,0x92,0x80,0x15,0xc5,0xda,0x51,0x8b,0x02,0x03,0x01,0x00,0x01,0xa3, +0x81,0xc3,0x30,0x81,0xc0,0x30,0x14,0x06,0x09,0x2b,0x06,0x01,0x04,0x01,0x82,0x37, +0x12,0x04,0x01,0x01,0xff,0x04,0x04,0x01,0x00,0x01,0x00,0x30,0x3c,0x06,0x09,0x2b, +0x06,0x01,0x04,0x01,0x82,0x37,0x12,0x02,0x01,0x01,0xff,0x04,0x2c,0x4d,0x00,0x69, +0x00,0x63,0x00,0x72,0x00,0x6f,0x00,0x73,0x00,0x6f,0x00,0x66,0x00,0x74,0x00,0x20, +0x00,0x43,0x00,0x6f,0x00,0x72,0x00,0x70,0x00,0x6f,0x00,0x72,0x00,0x61,0x00,0x74, +0x00,0x69,0x00,0x6f,0x00,0x6e,0x00,0x00,0x00,0x30,0x4c,0x06,0x09,0x2b,0x06,0x01, +0x04,0x01,0x82,0x37,0x12,0x05,0x01,0x01,0xff,0x04,0x3c,0x00,0x10,0x00,0x00,0x01, +0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x09,0x04,0x00,0x00,0x18,0x00,0x18,0x00,0x30, +0x00,0x01,0x00,0x32,0x00,0x33,0x00,0x36,0x00,0x2d,0x00,0x34,0x00,0x2e,0x00,0x30, +0x00,0x30,0x00,0x2d,0x00,0x45,0x00,0x58,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x1c,0x06,0x03,0x55,0x1d,0x23,0x01,0x01, +0xff,0x04,0x12,0x30,0x10,0xa1,0x07,0x81,0x05,0x4e,0x54,0x54,0x53,0x45,0x82,0x05, +0x01,0x00,0x00,0x00,0x01,0x30,0x09,0x06,0x05,0x2b,0x0e,0x03,0x02,0x1d,0x05,0x00, +0x03,0x41,0x00,0x7b,0x1d,0xfd,0x24,0xea,0xf2,0xe8,0x17,0xdd,0x88,0x7e,0xfd,0xee, +0x28,0x61,0x7a,0x02,0xc3,0x73,0xcf,0x32,0x0f,0x7c,0x66,0x87,0x31,0xa7,0xbe,0x1b, +0x31,0xe2,0x20,0xa5,0x76,0x91,0x68,0x97,0x53,0x9e,0x80,0xcd,0x2b,0xd0,0x8e,0x8b, +0x7f,0x89,0x1b,0x62,0xa8,0xf8,0xee,0x5e,0x56,0xbd,0x9c,0x6b,0x80,0x06,0x54,0xd3, +0xf0,0xbf,0xb2,0x31,0x00,0x01,0x00,0x14,0x00,0xc7,0x32,0xf2,0x5b,0x98,0x0e,0x04, +0x49,0xa0,0x27,0x7e,0xf5,0xf6,0x0f,0xda,0x08,0x1d,0xe9,0x79,0xd1,0x31,0xc6,0x50, +0x90,0x4a,0xd3,0x1f,0x1d,0xf0,0x65,0x0d,0xb6,0x1f,0xaf,0xc9,0x1d +}; + +/* Send license certificate and related data to the server */ +void rdp_send_cert(HCONN conn) +{ + mcs_init_data(conn); + prs_io_uint8s(&conn->out, precanned_cert_packet, sizeof(precanned_cert_packet)); + MARK_END(conn->out); + mcs_send_data(conn, MCS_GLOBAL_CHANNEL, True); +} + +/* Initialise RDP transport packet */ +void rdp_init(HCONN conn) +{ + mcs_init_data(conn); + PUSH_LAYER(conn->out, rdp_offset, 6); +} + +/* Transmit RDP transport packet */ +void rdp_send(HCONN conn, uint16 pdu_type) +{ + RDP_HEADER hdr; + int length; + + POP_LAYER(conn->out, rdp_offset); + length = conn->out.end - conn->out.offset; + rdp_make_header(&hdr, length, pdu_type, conn->mcs_userid); + rdp_io_header(&conn->out, &hdr); + mcs_send_data(conn, MCS_GLOBAL_CHANNEL, True); +} + +/* Initialise RDP transport data packet */ +void rdp_init_data(HCONN conn) +{ + mcs_init_data(conn); + PUSH_LAYER(conn->out, rdp_offset, 18); +} + +/* Transmit RDP transport data packet */ +void rdp_send_data(HCONN conn, uint16 data_pdu_type) +{ + RDP_HEADER hdr; + RDP_DATA_HEADER datahdr; + int length = conn->out.end - conn->out.offset; + + POP_LAYER(conn->out, rdp_offset); + length = conn->out.end - conn->out.offset; + rdp_make_header(&hdr, length, RDP_PDU_DATA, conn->mcs_userid); + rdp_io_header(&conn->out, &hdr); + rdp_make_data_header(&datahdr, 0x103ea, length, data_pdu_type); + rdp_io_data_header(&conn->out, &datahdr); + mcs_send_data(conn, MCS_GLOBAL_CHANNEL, True); +} + +void rdp_send_confirm_active(HCONN conn) +{ + RDP_ACTIVE_PDU active; + + rdp_init(conn); + rdp_make_active_pdu(&active, 0x103ea, conn->mcs_userid); + rdp_io_active_pdu(&conn->out, &active, RDP_PDU_CONFIRM_ACTIVE); + MARK_END(conn->out); + rdp_send(conn, RDP_PDU_CONFIRM_ACTIVE); +} + +void rdp_send_synchronize(HCONN conn) +{ + RDP_SYNCHRONIZE_PDU sync; + + rdp_init_data(conn); + rdp_make_synchronize_pdu(&sync, 1002); + rdp_io_synchronize_pdu(&conn->out, &sync); + MARK_END(conn->out); + rdp_send_data(conn, RDP_DATA_PDU_SYNCHRONIZE); +} + +void rdp_send_control(HCONN conn, uint16 action) +{ + RDP_CONTROL_PDU control; + + rdp_init_data(conn); + rdp_make_control_pdu(&control, action); + rdp_io_control_pdu(&conn->out, &control); + MARK_END(conn->out); + rdp_send_data(conn, RDP_DATA_PDU_CONTROL); +} + +void rdp_send_fonts(HCONN conn, uint16 seqno) +{ + RDP_FONT_PDU fonts; + + rdp_init_data(conn); + rdp_make_font_pdu(&fonts, seqno); + rdp_io_font_pdu(&conn->out, &fonts); + MARK_END(conn->out); + rdp_send_data(conn, RDP_DATA_PDU_FONT2); +} + +void rdp_send_input(HCONN conn) +{ + RDP_INPUT_PDU input; + + rdp_init_data(conn); + rdp_make_input_pdu(&input); + rdp_io_input_pdu(&conn->out, &input); + MARK_END(conn->out); + rdp_send_data(conn, RDP_DATA_PDU_INPUT); +} + +BOOL rdp_recv_pdu(HCONN conn, uint8 *type) +{ + RDP_HEADER hdr; + + if (!mcs_recv(conn, False) || !rdp_io_header(&conn->in, &hdr)) + return False; + + *type = hdr.pdu_type & 0xf; + return True; +} + +/* Disconnect from the RDP layer */ +void rdp_disconnect(HCONN conn) +{ + mcs_disconnect(conn); +} + +void rdp_make_header(RDP_HEADER *hdr, uint16 length, uint16 pdu_type, + uint16 userid) +{ + hdr->length = length; + hdr->pdu_type = pdu_type | 0x10; /* Version 1 */ + hdr->userid = userid + 1001; +} + +void rdp_make_data_header(RDP_DATA_HEADER *hdr, uint32 shareid, + uint16 length, uint16 data_pdu_type) +{ + hdr->shareid = shareid; + hdr->pad = 0; + hdr->streamid = 1; + hdr->length = length - 14; + hdr->data_pdu_type = data_pdu_type; + hdr->compress_type = 0; + hdr->compress_len = 0; +} + +void rdp_make_general_caps(RDP_GENERAL_CAPS *caps) +{ + caps->os_major_type = 1; + caps->os_minor_type = 3; + caps->ver_protocol = 0x200; +} + +void rdp_make_bitmap_caps(RDP_BITMAP_CAPS *caps) +{ + caps->preferred_bpp = 8; + caps->receive1bpp = 1; + caps->receive4bpp = 1; + caps->receive8bpp = 1; + caps->width = 640; + caps->height = 480; + caps->compression = 1; + caps->unknown2 = 1; +} + +void rdp_make_order_caps(RDP_ORDER_CAPS *caps) +{ + caps->xgranularity = 1; + caps->ygranularity = 20; + caps->max_order_level = 1; + caps->num_fonts = 0x147; + caps->cap_flags = 0x2A; + +// caps->cap_flags = ORDER_CAP_NEGOTIATE | ORDER_CAP_NOSUPPORT; + + caps->support[0] = caps->support[1] = caps->support[2] + = caps->support[3] = caps->support[4] = caps->support[5] + = caps->support[6] = caps->support[8] = caps->support[11] + = caps->support[12] = caps->support[22] = caps->support[28] + = caps->support[29] = caps->support[30] = 1; + caps->text_cap_flags = 0x6A1; + caps->desk_save_size = 0x38400; + caps->unknown2 = 0x4E4; +} + +void rdp_make_bmpcache_caps(RDP_BMPCACHE_CAPS *caps) +{ + caps->caches[0].entries = 0x258; + caps->caches[0].max_cell_size = 0x100; + caps->caches[1].entries = 0x12c; + caps->caches[1].max_cell_size = 0x400; + caps->caches[2].entries = 0x106; + caps->caches[2].max_cell_size = 0x1000; +} + +void rdp_make_control_caps(RDP_CONTROL_CAPS *caps) +{ + caps->control_interest = 2; + caps->detach_interest = 2; +} + +void rdp_make_activate_caps(RDP_ACTIVATE_CAPS *caps) +{ +} + +void rdp_make_pointer_caps(RDP_POINTER_CAPS *caps) +{ + caps->colour_pointer = 0; + caps->cache_size = 20; +} + +void rdp_make_share_caps(RDP_SHARE_CAPS *caps, uint16 userid) +{ +} + +void rdp_make_colcache_caps(RDP_COLCACHE_CAPS *caps) +{ + caps->cache_size = 6; +} + +void rdp_make_active_pdu(RDP_ACTIVE_PDU *pdu, uint32 shareid, uint16 userid) +{ + memset(pdu, 0, sizeof(*pdu)); + pdu->shareid = shareid; + pdu->userid = 1002; + pdu->source_len = sizeof(RDP_SOURCE); + memcpy(pdu->source, RDP_SOURCE, sizeof(RDP_SOURCE)); + + pdu->caps_len = RDP_CAPLEN_GENERAL + RDP_CAPLEN_BITMAP + RDP_CAPLEN_ORDER + + RDP_CAPLEN_BMPCACHE + RDP_CAPLEN_COLCACHE + RDP_CAPLEN_ACTIVATE + + RDP_CAPLEN_CONTROL + RDP_CAPLEN_POINTER + RDP_CAPLEN_SHARE + + RDP_CAPLEN_UNKNOWN; + pdu->num_caps = 0xD; + + rdp_make_general_caps (&pdu->general_caps ); + rdp_make_bitmap_caps (&pdu->bitmap_caps ); + rdp_make_order_caps (&pdu->order_caps ); + rdp_make_bmpcache_caps(&pdu->bmpcache_caps); + rdp_make_control_caps (&pdu->control_caps ); + rdp_make_activate_caps(&pdu->activate_caps); + rdp_make_pointer_caps (&pdu->pointer_caps ); + rdp_make_share_caps (&pdu->share_caps, userid); + rdp_make_colcache_caps(&pdu->colcache_caps); +} + +void rdp_make_control_pdu(RDP_CONTROL_PDU *pdu, uint16 action) +{ + pdu->action = action; + pdu->userid = 0; + pdu->controlid = 0; +} + +void rdp_make_synchronize_pdu(RDP_SYNCHRONIZE_PDU *pdu, uint16 userid) +{ + pdu->type = 1; + pdu->userid = userid; +} + +void rdp_make_font_pdu(RDP_FONT_PDU *pdu, uint16 seqno) +{ + pdu->num_fonts = 0; + pdu->unknown1 = 0x3e; + pdu->unknown2 = seqno; + pdu->entry_size = RDP_FONT_INFO_SIZE; +} + +void rdp_make_input_pdu(RDP_INPUT_PDU *pdu) +{ + uint32 now = time(NULL); + + pdu->num_events = 3; + pdu->pad = 0; + + pdu->event[0].event_time = now; + pdu->event[0].message_type = RDP_INPUT_SYNCHRONIZE; + pdu->event[0].device_flags = 0; + pdu->event[0].mouse_x = 0; + pdu->event[0].mouse_y = 0; + + pdu->event[1].event_time = now; + pdu->event[1].message_type = RDP_INPUT_UNKNOWN; + pdu->event[1].device_flags = 0x8000; + pdu->event[1].mouse_x = 15; + pdu->event[1].mouse_y = 0; + + pdu->event[2].event_time = now; + pdu->event[2].message_type = RDP_INPUT_MOUSE; + pdu->event[2].device_flags = MOUSE_FLAG_MOVE; + pdu->event[2].mouse_x = 425; + pdu->event[2].mouse_y = 493; +} + +BOOL rdp_io_header(STREAM s, RDP_HEADER *hdr) +{ + BOOL res = True; + + res = res ? lsb_io_uint16(s, &hdr->length ) : False; + res = res ? lsb_io_uint16(s, &hdr->pdu_type) : False; + res = res ? lsb_io_uint16(s, &hdr->userid ) : False; + + return res; +} + +BOOL rdp_io_data_header(STREAM s, RDP_DATA_HEADER *hdr) +{ + BOOL res = True; + + res = res ? lsb_io_uint32(s, &hdr->shareid ) : False; + res = res ? prs_io_uint8 (s, &hdr->pad ) : False; + res = res ? prs_io_uint8 (s, &hdr->streamid ) : False; + res = res ? lsb_io_uint16(s, &hdr->length ) : False; + res = res ? prs_io_uint8 (s, &hdr->data_pdu_type) : False; + res = res ? prs_io_uint8 (s, &hdr->compress_type) : False; + res = res ? lsb_io_uint16(s, &hdr->compress_len ) : False; + + return res; +} + +BOOL rdp_io_general_caps(STREAM s, RDP_GENERAL_CAPS *caps) +{ + uint16 length = RDP_CAPLEN_GENERAL; + uint16 pkt_length = length; + BOOL res; + + res = lsb_io_uint16(s, &pkt_length); + if (pkt_length != length) + { + fprintf(stderr, "Unrecognised capabilities size\n"); + return False; + } + + res = res ? lsb_io_uint16(s, &caps->os_major_type ) : False; + res = res ? lsb_io_uint16(s, &caps->os_minor_type ) : False; + res = res ? lsb_io_uint16(s, &caps->ver_protocol ) : False; + res = res ? lsb_io_uint16(s, &caps->pad1 ) : False; + res = res ? lsb_io_uint16(s, &caps->compress_types) : False; + res = res ? lsb_io_uint16(s, &caps->pad2 ) : False; + res = res ? lsb_io_uint16(s, &caps->cap_update ) : False; + res = res ? lsb_io_uint16(s, &caps->remote_unshare) : False; + res = res ? lsb_io_uint16(s, &caps->compress_level) : False; + res = res ? lsb_io_uint16(s, &caps->pad3 ) : False; + + return res; +} + +BOOL rdp_io_bitmap_caps(STREAM s, RDP_BITMAP_CAPS *caps) +{ + uint16 length = RDP_CAPLEN_BITMAP; + uint16 pkt_length = length; + BOOL res; + + res = lsb_io_uint16(s, &pkt_length); + if (pkt_length != length) + { + fprintf(stderr, "Unrecognised capabilities size\n"); + return False; + } + + res = res ? lsb_io_uint16(s, &caps->preferred_bpp) : False; + res = res ? lsb_io_uint16(s, &caps->receive1bpp ) : False; + res = res ? lsb_io_uint16(s, &caps->receive4bpp ) : False; + res = res ? lsb_io_uint16(s, &caps->receive8bpp ) : False; + res = res ? lsb_io_uint16(s, &caps->width ) : False; + res = res ? lsb_io_uint16(s, &caps->height ) : False; + res = res ? lsb_io_uint16(s, &caps->pad1 ) : False; + res = res ? lsb_io_uint16(s, &caps->allow_resize ) : False; + res = res ? lsb_io_uint16(s, &caps->compression ) : False; + res = res ? lsb_io_uint16(s, &caps->unknown1 ) : False; + res = res ? lsb_io_uint16(s, &caps->unknown2 ) : False; + res = res ? lsb_io_uint16(s, &caps->pad2 ) : False; + + return res; +} + +BOOL rdp_io_order_caps(STREAM s, RDP_ORDER_CAPS *caps) +{ + uint16 length = RDP_CAPLEN_ORDER; + uint16 pkt_length = length; + BOOL res; + + res = lsb_io_uint16(s, &pkt_length); + if (pkt_length != length) + { + fprintf(stderr, "Unrecognised capabilities size\n"); + return False; + } + + res = res ? prs_io_uint8s(s, caps->terminal_desc, 16) : False; + res = res ? lsb_io_uint32(s, &caps->pad1 ) : False; + res = res ? lsb_io_uint16(s, &caps->xgranularity ) : False; + res = res ? lsb_io_uint16(s, &caps->ygranularity ) : False; + res = res ? lsb_io_uint16(s, &caps->pad2 ) : False; + res = res ? lsb_io_uint16(s, &caps->max_order_level ) : False; + res = res ? lsb_io_uint16(s, &caps->num_fonts ) : False; + res = res ? lsb_io_uint16(s, &caps->cap_flags ) : False; + res = res ? prs_io_uint8s(s, caps->support , 32) : False; + res = res ? lsb_io_uint16(s, &caps->text_cap_flags ) : False; + res = res ? lsb_io_uint16(s, &caps->pad3 ) : False; + res = res ? lsb_io_uint32(s, &caps->pad4 ) : False; + res = res ? lsb_io_uint32(s, &caps->desk_save_size ) : False; + res = res ? lsb_io_uint32(s, &caps->unknown1 ) : False; + res = res ? lsb_io_uint32(s, &caps->unknown2 ) : False; + + return res; +} + +BOOL rdp_io_bmpcache_info(STREAM s, RDP_BMPCACHE_INFO *info) +{ + if (!lsb_io_uint16(s, &info->entries )) + return False; + + if (!lsb_io_uint16(s, &info->max_cell_size)) + return False; + + return True; +} + +BOOL rdp_io_bmpcache_caps(STREAM s, RDP_BMPCACHE_CAPS *caps) +{ + uint16 length = RDP_CAPLEN_BMPCACHE; + uint16 pkt_length = length; + BOOL res; + int i; + + res = lsb_io_uint16(s, &pkt_length); + if (pkt_length != length) + { + fprintf(stderr, "Unrecognised capabilities size\n"); + return False; + } + + for (i = 0; i < 6; i++) + res = res ? lsb_io_uint32(s, &caps->unused[i]) : False; + + for (i = 0; i < 3; i++) + res = res ? rdp_io_bmpcache_info(s, &caps->caches[i]) : False; + + return res; +} + +BOOL rdp_io_control_caps(STREAM s, RDP_CONTROL_CAPS *caps) +{ + uint16 length = RDP_CAPLEN_CONTROL; + uint16 pkt_length = length; + BOOL res; + + res = lsb_io_uint16(s, &pkt_length); + if (pkt_length != length) + { + fprintf(stderr, "Unrecognised capabilities size\n"); + return False; + } + + res = res ? lsb_io_uint16(s, &caps->control_caps ) : False; + res = res ? lsb_io_uint16(s, &caps->remote_detach ) : False; + res = res ? lsb_io_uint16(s, &caps->control_interest) : False; + res = res ? lsb_io_uint16(s, &caps->detach_interest ) : False; + + return res; +} + +BOOL rdp_io_activate_caps(STREAM s, RDP_ACTIVATE_CAPS *caps) +{ + uint16 length = RDP_CAPLEN_ACTIVATE; + uint16 pkt_length = length; + BOOL res; + + res = lsb_io_uint16(s, &pkt_length); + if (pkt_length != length) + { + fprintf(stderr, "Unrecognised capabilities size\n"); + return False; + } + + res = res ? lsb_io_uint16(s, &caps->help_key ) : False; + res = res ? lsb_io_uint16(s, &caps->help_index_key ) : False; + res = res ? lsb_io_uint16(s, &caps->help_extended_key) : False; + res = res ? lsb_io_uint16(s, &caps->window_activate ) : False; + + return res; +} + +BOOL rdp_io_pointer_caps(STREAM s, RDP_POINTER_CAPS *caps) +{ + uint16 length = RDP_CAPLEN_POINTER; + uint16 pkt_length = length; + BOOL res; + + res = lsb_io_uint16(s, &pkt_length); + if (pkt_length != length) + { + fprintf(stderr, "Unrecognised capabilities size\n"); + return False; + } + + res = res ? lsb_io_uint16(s, &caps->colour_pointer) : False; + res = res ? lsb_io_uint16(s, &caps->cache_size ) : False; + + return res; +} + +BOOL rdp_io_share_caps(STREAM s, RDP_SHARE_CAPS *caps) +{ + uint16 length = RDP_CAPLEN_SHARE; + uint16 pkt_length = length; + BOOL res; + + res = lsb_io_uint16(s, &pkt_length); + if (pkt_length != length) + { + fprintf(stderr, "Unrecognised capabilities size\n"); + return False; + } + + res = res ? lsb_io_uint16(s, &caps->userid) : False; + res = res ? lsb_io_uint16(s, &caps->pad ) : False; + + return res; +} + +BOOL rdp_io_colcache_caps(STREAM s, RDP_COLCACHE_CAPS *caps) +{ + uint16 length = RDP_CAPLEN_COLCACHE; + uint16 pkt_length = length; + BOOL res; + + res = lsb_io_uint16(s, &pkt_length); + if (pkt_length != length) + { + fprintf(stderr, "Unrecognised capabilities size\n"); + return False; + } + + res = res ? lsb_io_uint16(s, &caps->cache_size) : False; + res = res ? lsb_io_uint16(s, &caps->pad ) : False; + + return res; +} + +uint8 canned_caps[] = { +0x01,0x00,0x00,0x00,0x09,0x04,0x00,0x00,0x04, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0C,0x00,0x08,0x00,0x01, +0x00,0x00,0x00,0x0E,0x00,0x08,0x00,0x01,0x00,0x00,0x00,0x10,0x00,0x34,0x00,0xFE, +0x00,0x04,0x00,0xFE,0x00,0x04,0x00,0xFE,0x00,0x08,0x00,0xFE,0x00,0x08,0x00,0xFE, +0x00,0x10,0x00,0xFE,0x00,0x20,0x00,0xFE,0x00,0x40,0x00,0xFE,0x00,0x80,0x00,0xFE, +0x00,0x00,0x01,0x40,0x00,0x00,0x08,0x00,0x01,0x00,0x01,0x02,0x00,0x00,0x00 +}; + +BOOL rdp_io_unknown_caps(STREAM s, void *caps) +{ + uint16 length = 0x58; + uint16 pkt_length = length; + BOOL res; + + res = lsb_io_uint16(s, &pkt_length); + if (pkt_length != length) + { + fprintf(stderr, "Unrecognised capabilities size\n"); + return False; + } + + res = res ? prs_io_uint8s(s, canned_caps, RDP_CAPLEN_UNKNOWN-4) : False; + + return res; +} + +BOOL rdp_io_active_pdu(STREAM s, RDP_ACTIVE_PDU *pdu, int pdutype) +{ + uint16 capset; + uint16 length; + BOOL res; + int i; + + res = lsb_io_uint32(s, &pdu->shareid); + + if (pdutype == RDP_PDU_CONFIRM_ACTIVE) + res = res ? lsb_io_uint16(s, &pdu->userid ) : False; + + res = res ? lsb_io_uint16(s, &pdu->source_len) : False; + res = res ? lsb_io_uint16(s, &pdu->caps_len ) : False; + + if (pdu->source_len > 48) + { + fprintf(stderr, "RDP source descriptor too long\n"); + return False; + } + + res = res ? prs_io_uint8s(s, pdu->source, pdu->source_len) : False; + res = res ? lsb_io_uint16(s, &pdu->num_caps ) : False; + res = res ? lsb_io_uint16(s, &pdu->pad ) : False; + + if (s->marshall) + { + capset = RDP_CAPSET_GENERAL; + res = res ? lsb_io_uint16(s, &capset) : False; + res = res ? rdp_io_general_caps(s, &pdu->general_caps) : False; + + capset = RDP_CAPSET_BITMAP; + res = res ? lsb_io_uint16(s, &capset) : False; + res = res ? rdp_io_bitmap_caps (s, &pdu->bitmap_caps ) : False; + + capset = RDP_CAPSET_ORDER; + res = res ? lsb_io_uint16(s, &capset) : False; + res = res ? rdp_io_order_caps (s, &pdu->order_caps ) : False; + + capset = RDP_CAPSET_BMPCACHE; + res = res ? lsb_io_uint16(s, &capset) : False; + res = res ? rdp_io_bmpcache_caps(s, &pdu->bmpcache_caps) : False; + + capset = RDP_CAPSET_COLCACHE; + res = res ? lsb_io_uint16(s, &capset) : False; + res = res ? rdp_io_colcache_caps(s, &pdu->colcache_caps) : False; + + capset = RDP_CAPSET_ACTIVATE; + res = res ? lsb_io_uint16(s, &capset) : False; + res = res ? rdp_io_activate_caps(s, &pdu->activate_caps) : False; + + capset = RDP_CAPSET_CONTROL; + res = res ? lsb_io_uint16(s, &capset) : False; + res = res ? rdp_io_control_caps(s, &pdu->control_caps) : False; + + capset = RDP_CAPSET_POINTER; + res = res ? lsb_io_uint16(s, &capset) : False; + res = res ? rdp_io_pointer_caps(s, &pdu->pointer_caps) : False; + + capset = RDP_CAPSET_SHARE; + res = res ? lsb_io_uint16(s, &capset) : False; + res = res ? rdp_io_share_caps (s, &pdu->share_caps ) : False; + + capset = RDP_CAPSET_UNKNOWN; + res = res ? lsb_io_uint16(s, &capset) : False; + res = res ? rdp_io_unknown_caps(s, NULL) : False; + } + else + { + for (i = 0; i < pdu->num_caps; i++) + { + if (!res) + return False; + + if (!lsb_io_uint16(s, &capset)) + return False; + + switch (capset) + { + case RDP_CAPSET_GENERAL: + res = rdp_io_general_caps (s, &pdu->general_caps ); + break; + case RDP_CAPSET_BITMAP: + res = rdp_io_bitmap_caps (s, &pdu->bitmap_caps ); + break; + case RDP_CAPSET_ORDER: + res = rdp_io_order_caps (s, &pdu->order_caps ); + break; + case RDP_CAPSET_BMPCACHE: + res = rdp_io_bmpcache_caps(s, &pdu->bmpcache_caps); + break; + case RDP_CAPSET_CONTROL: + res = rdp_io_control_caps (s, &pdu->control_caps ); + break; + case RDP_CAPSET_ACTIVATE: + res = rdp_io_activate_caps(s, &pdu->activate_caps); + break; + case RDP_CAPSET_POINTER: + res = rdp_io_pointer_caps (s, &pdu->pointer_caps ); + break; + case RDP_CAPSET_SHARE: + res = rdp_io_share_caps (s, &pdu->share_caps ); + break; + case RDP_CAPSET_COLCACHE: + res = rdp_io_colcache_caps(s, &pdu->colcache_caps); + break; + default: + fprintf(stderr, "Warning: Unrecognised capset %x\n", + capset); + + if (!lsb_io_uint16(s, &length)) + return False; + + s->offset += (length - 4); + } + } + } + + return res; +} + +BOOL rdp_io_control_pdu(STREAM s, RDP_CONTROL_PDU *pdu) +{ + BOOL res = True; + + res = res ? lsb_io_uint16(s, &pdu->action ) : False; + res = res ? lsb_io_uint16(s, &pdu->userid ) : False; + res = res ? lsb_io_uint32(s, &pdu->controlid) : False; + + return res; +} + +BOOL rdp_io_synchronize_pdu(STREAM s, RDP_SYNCHRONIZE_PDU *pdu) +{ + BOOL res = True; + + res = res ? lsb_io_uint16(s, &pdu->type ) : False; + res = res ? lsb_io_uint16(s, &pdu->userid) : False; + + return res; +} + +BOOL rdp_io_input_event(STREAM s, RDP_INPUT_EVENT *evt) +{ + BOOL res = True; + + res = res ? lsb_io_uint32(s, &evt->event_time) : False; + res = res ? lsb_io_uint16(s, &evt->message_type) : False; + + if (!res) + return False; + + switch (evt->message_type) + { + case RDP_INPUT_CODEPOINT: + case RDP_INPUT_VIRTKEY: + res = res ? lsb_io_uint16(s, &evt->device_flags) : False; + res = res ? lsb_io_uint16(s, &evt->kbd_keycode ) : False; + break; + case RDP_INPUT_SYNCHRONIZE: + case RDP_INPUT_UNKNOWN: + case RDP_INPUT_MOUSE: + res = res ? lsb_io_uint16(s, &evt->device_flags) : False; + res = res ? lsb_io_uint16(s, &evt->mouse_x ) : False; + res = res ? lsb_io_uint16(s, &evt->mouse_y ) : False; + break; + default: + fprintf(stderr, "Unknown input type %d\n", evt->message_type); + return False; + } + + return res; +} + +BOOL rdp_io_input_pdu(STREAM s, RDP_INPUT_PDU *pdu) +{ + BOOL res = True; + int i; + + res = res ? lsb_io_uint16(s, &pdu->num_events) : False; + res = res ? lsb_io_uint16(s, &pdu->pad ) : False; + + if (pdu->num_events > RDP_MAX_EVENTS) + { + fprintf(stderr, "Too many events in one PDU\n"); + return False; + } + + for (i = 0; i < pdu->num_events; i++) + { + res = res ? rdp_io_input_event(s, &pdu->event[i]) : False; + } + + return res; +} + +BOOL rdp_io_font_info(STREAM s, RDP_FONT_INFO *font) +{ + BOOL res = True; + + res = res ? prs_io_uint8s(s, font->name, 32 ) : False; + res = res ? lsb_io_uint16(s, &font->flags ) : False; + res = res ? lsb_io_uint16(s, &font->width ) : False; + res = res ? lsb_io_uint16(s, &font->height ) : False; + res = res ? lsb_io_uint16(s, &font->xaspect ) : False; + res = res ? lsb_io_uint16(s, &font->yaspect ) : False; + res = res ? lsb_io_uint32(s, &font->signature) : False; + res = res ? lsb_io_uint16(s, &font->codepage ) : False; + res = res ? lsb_io_uint16(s, &font->ascent ) : False; + + return res; +} + +BOOL rdp_io_font_pdu(STREAM s, RDP_FONT_PDU *pdu) +{ + BOOL res = True; + int i; + + res = res ? lsb_io_uint16(s, &pdu->num_fonts ) : False; + res = res ? lsb_io_uint16(s, &pdu->unknown1 ) : False; + res = res ? lsb_io_uint16(s, &pdu->unknown2 ) : False; + res = res ? lsb_io_uint16(s, &pdu->entry_size) : False; + + if (pdu->num_fonts > RDP_MAX_FONTS) + { + fprintf(stderr, "Too many fonts in one PDU\n"); + return False; + } + + for (i = 0; i < pdu->num_fonts; i++) + { + res = res ? rdp_io_font_info(s, &pdu->font[i]) : False; + } + + return res; +} + +BOOL rdp_io_update_pdu(STREAM s, RDP_UPDATE_PDU *pdu) +{ + BOOL res = True; + + res = res ? lsb_io_uint16(s, &pdu->update_type) : False; + res = res ? lsb_io_uint16(s, &pdu->pad ) : False; + + return res; +} + +BOOL rdp_io_secondary_order(STREAM s, RDP_SECONDARY_ORDER *rso) +{ + BOOL res = True; + + res = res ? lsb_io_uint16(s, &rso->length) : False; + res = res ? lsb_io_uint16(s, &rso->flags ) : False; + res = res ? prs_io_uint8 (s, &rso->type ) : False; + + return res; +} + +BOOL rdp_io_bitmap_header(STREAM s, RDP_BITMAP_HEADER *rdh) +{ + BOOL res = True; + + res = res ? prs_io_uint8 (s, &rdh->cache_id ) : False; + res = res ? prs_io_uint8 (s, &rdh->pad1 ) : False; + res = res ? prs_io_uint8 (s, &rdh->width ) : False; + res = res ? prs_io_uint8 (s, &rdh->height ) : False; + res = res ? prs_io_uint8 (s, &rdh->bpp ) : False; + res = res ? lsb_io_uint16(s, &rdh->bufsize ) : False; + res = res ? lsb_io_uint16(s, &rdh->cache_idx ) : False; + res = res ? lsb_io_uint16(s, &rdh->pad2 ) : False; + res = res ? lsb_io_uint16(s, &rdh->size ) : False; + res = res ? lsb_io_uint16(s, &rdh->row_size ) : False; + res = res ? lsb_io_uint16(s, &rdh->final_size) : False; + + return res; +} diff --git a/rdp.h b/rdp.h new file mode 100644 index 0000000..5681ac8 --- /dev/null +++ b/rdp.h @@ -0,0 +1,375 @@ +/* + rdesktop: A Remote Desktop Protocol client. + Protocol services - RDP layer + Copyright (C) Matthew Chapman 1999-2000 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +enum RDP_PDU_TYPE +{ + RDP_PDU_DEMAND_ACTIVE = 1, + RDP_PDU_CONFIRM_ACTIVE = 3, + RDP_PDU_DATA = 7 +}; + +enum RDP_DATA_PDU_TYPE +{ + RDP_DATA_PDU_UPDATE = 2, + RDP_DATA_PDU_CONTROL = 20, + RDP_DATA_PDU_POINTER = 27, + RDP_DATA_PDU_INPUT = 28, + RDP_DATA_PDU_SYNCHRONIZE = 31, + RDP_DATA_PDU_FONT2 = 39 +}; + +typedef struct _RDP_HEADER +{ + uint16 length; + uint16 pdu_type; + uint16 userid; + +} RDP_HEADER; + +typedef struct _RDP_DATA_HEADER +{ + uint32 shareid; + uint8 pad; + uint8 streamid; + uint16 length; + uint8 data_pdu_type; + uint8 compress_type; + uint16 compress_len; + +} RDP_DATA_HEADER; + +#define RDP_CAPSET_GENERAL 1 +#define RDP_CAPLEN_GENERAL 0x18 +#define OS_MAJOR_TYPE_UNIX 4 +#define OS_MINOR_TYPE_XSERVER 7 + +typedef struct _RDP_GENERAL_CAPS +{ + uint16 os_major_type; + uint16 os_minor_type; + uint16 ver_protocol; + uint16 pad1; + uint16 compress_types; + uint16 pad2; + uint16 cap_update; + uint16 remote_unshare; + uint16 compress_level; + uint16 pad3; + +} RDP_GENERAL_CAPS; + +#define RDP_CAPSET_BITMAP 2 +#define RDP_CAPLEN_BITMAP 0x1C + +typedef struct _RDP_BITMAP_CAPS +{ + uint16 preferred_bpp; + uint16 receive1bpp; + uint16 receive4bpp; + uint16 receive8bpp; + uint16 width; + uint16 height; + uint16 pad1; + uint16 allow_resize; + uint16 compression; + uint16 unknown1; + uint16 unknown2; + uint16 pad2; + +} RDP_BITMAP_CAPS; + +#define RDP_CAPSET_ORDER 3 +#define RDP_CAPLEN_ORDER 0x58 +#define ORDER_CAP_NEGOTIATE 2 +#define ORDER_CAP_NOSUPPORT 4 + +typedef struct _RDP_ORDER_CAPS +{ + uint8 terminal_desc[16]; + uint32 pad1; + uint16 xgranularity; // 1 + uint16 ygranularity; // 20 + uint16 pad2; + uint16 max_order_level; + uint16 num_fonts; // 0x2C + uint16 cap_flags; // 0x22 + uint8 support[32]; + uint16 text_cap_flags; // 0x6A1 + uint16 pad3; + uint32 pad4; + uint32 desk_save_size; + uint32 unknown1; // 1 from server, 0 from client + uint32 unknown2; // 0x4E4 from client + +} RDP_ORDER_CAPS; + +#define RDP_CAPSET_BMPCACHE 4 +#define RDP_CAPLEN_BMPCACHE 0x28 + +typedef struct _RDP_BMPCACHE_INFO +{ + uint16 entries; + uint16 max_cell_size; + +} RDP_BMPCACHE_INFO; + +typedef struct _RDP_BMPCACHE_CAPS +{ + uint32 unused[6]; + RDP_BMPCACHE_INFO caches[3]; + +} RDP_BMPCACHE_CAPS; + +#define RDP_CAPSET_CONTROL 5 +#define RDP_CAPLEN_CONTROL 0x0C + +typedef struct _RDP_CONTROL_CAPS +{ + uint16 control_caps; + uint16 remote_detach; + uint16 control_interest; + uint16 detach_interest; + +} RDP_CONTROL_CAPS; + +#define RDP_CAPSET_ACTIVATE 7 +#define RDP_CAPLEN_ACTIVATE 0x0C + +typedef struct _RDP_ACTIVATE_CAPS +{ + uint16 help_key; + uint16 help_index_key; + uint16 help_extended_key; + uint16 window_activate; + +} RDP_ACTIVATE_CAPS; + +#define RDP_CAPSET_POINTER 8 +#define RDP_CAPLEN_POINTER 0x08 + +typedef struct _RDP_POINTER_CAPS +{ + uint16 colour_pointer; + uint16 cache_size; + +} RDP_POINTER_CAPS; + +#define RDP_CAPSET_SHARE 9 +#define RDP_CAPLEN_SHARE 0x08 + +typedef struct _RDP_SHARE_CAPS +{ + uint16 userid; + uint16 pad; + +} RDP_SHARE_CAPS; + +#define RDP_CAPSET_COLCACHE 10 +#define RDP_CAPLEN_COLCACHE 0x08 + +typedef struct _RDP_COLCACHE_CAPS +{ + uint16 cache_size; + uint16 pad; + +} RDP_COLCACHE_CAPS; + +#define RDP_CAPSET_UNKNOWN 13 +#define RDP_CAPLEN_UNKNOWN 0x9C + +#define RDP_SOURCE "MSTSC" + +typedef struct _RDP_ACTIVE_PDU +{ + uint32 shareid; + uint16 userid; // RDP_PDU_CONFIRM_ACTIVE only + uint16 source_len; + uint16 caps_len; + uint8 source[48]; + uint16 num_caps; + uint16 pad; + + RDP_GENERAL_CAPS general_caps; + RDP_BITMAP_CAPS bitmap_caps; + RDP_ORDER_CAPS order_caps; + RDP_BMPCACHE_CAPS bmpcache_caps; + RDP_ACTIVATE_CAPS activate_caps; + RDP_CONTROL_CAPS control_caps; + RDP_POINTER_CAPS pointer_caps; + RDP_SHARE_CAPS share_caps; + RDP_COLCACHE_CAPS colcache_caps; + +} RDP_ACTIVE_PDU; + +typedef struct _RDP_SYNCHRONIZE_PDU +{ + uint16 type; // 1 + uint16 userid; + +} RDP_SYNCHRONIZE_PDU; + +#define RDP_CTL_REQUEST_CONTROL 1 +#define RDP_CTL_GRANT_CONTROL 2 +#define RDP_CTL_DETACH 3 +#define RDP_CTL_COOPERATE 4 + +typedef struct _RDP_CONTROL_PDU +{ + uint16 action; // see above + uint16 userid; + uint32 controlid; + +} RDP_CONTROL_PDU; + +#define RDP_INPUT_SYNCHRONIZE 0 +#define RDP_INPUT_CODEPOINT 1 +#define RDP_INPUT_VIRTKEY 2 +#define RDP_INPUT_UNKNOWN 4 +#define RDP_INPUT_MOUSE 0x8001 + +#define KBD_FLAG_RIGHT 0x0001 +#define KBD_FLAG_QUIET 0x1000 +#define KBD_FLAG_DOWN 0x4000 +#define KBD_FLAG_RELEASE 0x8000 + +#define MOUSE_FLAG_MOVE 0x0800 +#define MOUSE_FLAG_BUTTON1 0x1000 +#define MOUSE_FLAG_BUTTON2 0x2000 +#define MOUSE_FLAG_BUTTON3 0x4000 +#define MOUSE_FLAG_DOWN 0x8000 + +#define RDP_MAX_EVENTS 50 + +typedef struct _RDP_INPUT_EVENT +{ + uint32 event_time; + uint16 message_type; + uint16 device_flags; + + uint16 kbd_keycode; + + uint16 mouse_x; + uint16 mouse_y; + +} RDP_INPUT_EVENT; + +typedef struct _RDP_INPUT_PDU +{ + uint16 num_events; + uint16 pad; + RDP_INPUT_EVENT event[RDP_MAX_EVENTS]; + +} RDP_INPUT_PDU; + +#define RDP_FONT_INFO_SIZE 0x32 +#define RDP_MAX_FONTS 100 + +typedef struct _RDP_FONT_INFO +{ + uint8 name[32]; + uint16 flags; + uint16 width; + uint16 height; + uint16 xaspect; + uint16 yaspect; + uint32 signature; + uint16 codepage; + uint16 ascent; + +} RDP_FONT_INFO; + +typedef struct _RDP_FONT_PDU +{ + uint16 num_fonts; + uint16 unknown1; // 0x3e + uint16 unknown2; // series number? + uint16 entry_size; + RDP_FONT_INFO font[RDP_MAX_FONTS]; + +} RDP_FONT_PDU; + +#define RDP_UPDATE_ORDERS 0 +#define RDP_UPDATE_PALETTE 2 + +typedef struct _OPAQUE_RECT_ORDER +{ + uint16 x; + uint16 y; + uint16 cx; + uint16 cy; + uint8 colour; + +} OPAQUE_RECT_ORDER; + +typedef struct _RDP_ORDER_STATE +{ + uint8 order_type; + + OPAQUE_RECT_ORDER opaque_rect; + +} RDP_ORDER_STATE; + +typedef struct _RDP_UPDATE_PDU +{ + uint16 update_type; + uint16 pad; + +} RDP_UPDATE_PDU; + +#define RDP_ORDER_STANDARD 1 +#define RDP_ORDER_SECONDARY 2 +#define RDP_ORDER_BOUNDS 4 +#define RDP_ORDER_CHANGE 8 +#define RDP_ORDER_DELTA 16 +#define RDP_ORDER_REPEAT 64 + +enum RDP_ORDER_TYPE +{ + RDP_ORDER_OPAQUE_RECT = 10 +}; + +enum RDP_SECONDARY_ORDER_TYPE +{ + RDP_ORDER_BMPCACHE = 2 +}; + +typedef struct _RDP_SECONDARY_ORDER +{ + uint16 length; + uint16 flags; + uint8 type; + +} RDP_SECONDARY_ORDER; + +typedef struct _RDP_BITMAP_HEADER +{ + uint8 cache_id; + uint8 pad1; + uint8 width; + uint8 height; + uint8 bpp; + uint16 bufsize; + uint16 cache_idx; + uint16 pad2; + uint16 size; + uint16 row_size; + uint16 final_size; + +} RDP_BITMAP_HEADER; diff --git a/tcp.c b/tcp.c new file mode 100644 index 0000000..ecb4eaf --- /dev/null +++ b/tcp.c @@ -0,0 +1,124 @@ +/* + rdesktop: A Remote Desktop Protocol client. + Protocol services - TCP layer + Copyright (C) Matthew Chapman 1999-2000 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" + +/* Establish a connection on the TCP layer */ +HCONN tcp_connect(char *server) +{ + struct hostent *nslookup; + struct sockaddr_in servaddr; + struct connection *conn; + int sock; + int true = 1; + + if ((nslookup = gethostbyname(server)) != NULL) + { + memcpy(&servaddr.sin_addr, nslookup->h_addr, sizeof(servaddr.sin_addr)); + } + else if (!inet_aton(server, &servaddr.sin_addr)) + { + fprintf(stderr, "%s: unable to resolve host\n", server); + return NULL; + } + + if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) + { + fprintf(stderr, "socket: %s\n", strerror(errno)); + return NULL; + } + + servaddr.sin_family = AF_INET; + servaddr.sin_port = htons(TCP_PORT_RDP); + + if (connect(sock, (struct sockaddr *)&servaddr, sizeof(struct sockaddr)) < 0) + { + fprintf(stderr, "connect: %s\n", strerror(errno)); + close(sock); + return NULL; + } + + setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &true, sizeof(true)); + + conn = xmalloc(sizeof(struct connection)); + STREAM_INIT(conn->in, False); + STREAM_INIT(conn->out, True); + + conn->tcp_socket = sock; + return conn; +} + +/* Disconnect on the TCP layer */ +void tcp_disconnect(HCONN conn) +{ + close(conn->tcp_socket); + free(conn); +} + +/* Send TCP transport data packet */ +BOOL tcp_send(HCONN conn) +{ + int length = conn->out.end; + int sent, total = 0; + + while (total < length) + { + sent = write(conn->tcp_socket, conn->out.data + total, + length - total); + + if (sent <= 0) + { + fprintf(stderr, "write: %s\n", strerror(errno)); + return False; + } + + total += sent; + } + + conn->out.offset = 0; + conn->out.end = conn->out.size; + return True; +} + +/* Receive a message on the TCP layer */ +BOOL tcp_recv(HCONN conn, int length) +{ + int rcvd; + + STREAM_SIZE(conn->in, length); + conn->in.end = conn->in.offset = 0; + + while (length > 0) + { + rcvd = read(conn->tcp_socket, conn->in.data + conn->in.end, + length); + + if (rcvd <= 0) + { + fprintf(stderr, "read: %s\n", strerror(errno)); + return False; + } + + conn->in.end += rcvd; + length -= rcvd; + } + + return True; +} diff --git a/tcp.h b/tcp.h new file mode 100644 index 0000000..b867765 --- /dev/null +++ b/tcp.h @@ -0,0 +1,22 @@ +/* + rdesktop: A Remote Desktop Protocol client. + Protocol services - TCP layer + Copyright (C) Matthew Chapman 1999-2000 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +/* Port number for Remote Desktop Protocol */ +#define TCP_PORT_RDP 3389