pax_global_header00006660000000000000000000000064120315513050014505gustar00rootroot0000000000000052 comment=13a69b8f68f1eb796bb4328ce99ed6f42d19f8b8 xrdp-0.6.0/000077500000000000000000000000001203155130500124655ustar00rootroot00000000000000xrdp-0.6.0/.gitignore000066400000000000000000000005721203155130500144610ustar00rootroot00000000000000*~ aclocal.m4 AUTHORS autom4te.cache/ ChangeLog config_ac.h config_ac-h.in config.c config.guess config.log config.status config.sub configure depcomp .deps/ install-sh *.la .libs libtool *.lo ltmain.sh Makefile Makefile.in missing NEWS *.o README stamp-h1 xrdp-chansrv xrdp-genkeymap xrdp-keygen xrdp-sesadmin xrdp-sesman xrdp-sesrun xrdp-sessvc xrdp-sestest xrdp-dis xrdp/xrdpxrdp-0.6.0/COPYING000066400000000000000000000455771203155130500135420ustar00rootroot00000000000000 special clause for libxrdp and librdp, both based on rdesktop these libraries link to openssl This software is released under the GNU General Public License (reproduced below) with the additional exemption that compiling, linking, and/or using OpenSSL together with this software is allowed. --- special clause for xrdp, that main executable for linking with proprietary modules Linking this library statically or dynamically with other modules is making a combined work based on this library. Thus, the terms and conditions of the GNU General Public License cover the whole combination. As a special exception, the copyright holders of this library give you permission to link this library with independent modules to produce an executable, regardless of the license terms of these independent modules, and to copy and distribute the resulting executable under terms of your choice, provided that you also meet, for each linked independent module, the terms and conditions of the license of that module. An independent module is a module which is not derived from or based on this library. If you modify this library, you may extend this exception to your version of the library, but you are not obliged to do so. If you do not wish to do so, delete this exception statement from your version. --- 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. xrdp-0.6.0/Makefile.am000066400000000000000000000006021203155130500145170ustar00rootroot00000000000000EXTRA_DIST = bootstrap COPYING design.txt faq-compile.txt faq-general.txt file-loc.txt install.txt prog_std.txt readme.txt if XRDP_FREERDP FREERDPDIR = freerdp else if XRDP_FREERDP1 FREERDPDIR = freerdp1 else FREERDPDIR = endif endif SUBDIRS = \ common \ vnc \ rdp \ xup \ mc \ $(FREERDPDIR) \ libxrdp \ xrdp \ sesman \ keygen \ docs \ instfiles \ genkeymap xrdp-0.6.0/bootstrap000077500000000000000000000006161203155130500144330ustar00rootroot00000000000000#!/bin/sh which autoconf if ! test $? -eq 0 then echo "error, install autoconf" exit 1 fi which automake if ! test $? -eq 0 then echo "error, install automake" exit 1 fi which libtool if ! test $? -eq 0 then echo "error, install libtool" exit 1 fi touch configure.ac touch NEWS touch AUTHORS touch README touch ChangeLog ln -s ../config.c $PWD/sesman/tools/config.c autoreconf -fvi xrdp-0.6.0/common/000077500000000000000000000000001203155130500137555ustar00rootroot00000000000000xrdp-0.6.0/common/Makefile.am000066400000000000000000000010551203155130500160120ustar00rootroot00000000000000EXTRA_DIST = d3des.h arch.h os_calls.h list.h file.h parse.h defines.h file_loc.h log.h os_calls.h ssl_calls.h thread_calls.h trans.h xrdp_constants.h AM_CFLAGS = \ -DXRDP_CFG_PATH=\"${sysconfdir}/xrdp\" \ -DXRDP_SBIN_PATH=\"${sbindir}\" \ -DXRDP_SHARE_PATH=\"${datadir}/xrdp\" \ -DXRDP_PID_PATH=\"${localstatedir}/run\" lib_LTLIBRARIES = \ libcommon.la libcommon_la_SOURCES = \ d3des.c \ file.c \ list.c \ log.c \ os_calls.c \ ssl_calls.c \ thread_calls.c \ trans.c libcommon_la_LIBADD = \ -lcrypto \ -lssl \ -lpthread xrdp-0.6.0/common/arch.h000066400000000000000000000056211203155130500150470ustar00rootroot00000000000000/* Copyright (c) 2004-2012 Jay Sorg Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #if !defined(ARCH_H) #define ARCH_H #if !(defined(L_ENDIAN) || defined(B_ENDIAN)) /* check endianess */ #if defined(__sparc__) || defined(__PPC__) || defined(__ppc__) || \ defined(__hppa__) #define B_ENDIAN #else #define L_ENDIAN #endif /* check if we need to align data */ #if defined(__sparc__) || defined(__alpha__) || defined(__hppa__) || \ defined(__AIX__) || defined(__PPC__) || defined(__mips__) || \ defined(__ia64__) || defined(__ppc__) || defined(__arm__) #define NEED_ALIGN #endif #endif /* defines for thread creation factory functions */ #if defined(_WIN32) #define THREAD_RV unsigned long #define THREAD_CC __stdcall #else #define THREAD_RV void* #define THREAD_CC #endif #if defined(__BORLANDC__) || defined(_WIN32) #define APP_CC __fastcall #define DEFAULT_CC __cdecl #else #define APP_CC #define DEFAULT_CC #endif #if defined(_WIN32) #if defined(__BORLANDC__) #define EXPORT_CC _export __cdecl #else #define EXPORT_CC #endif #else #define EXPORT_CC #endif typedef char ti8; typedef unsigned char tui8; typedef signed char tsi8; typedef short ti16; typedef unsigned short tui16; typedef signed short tsi16; typedef int ti32; typedef unsigned int tui32; typedef signed int tsi32; #if defined(_WIN64) /* Microsoft's VC++ compiler uses the more backwards-compatible LLP64 model. Most other 64 bit compilers(Solaris, AIX, HP, Linux, Mac OS X) use the LP64 model. long is 32 bits in LLP64 model, 64 bits in LP64 model. */ typedef __int64 tbus; #else typedef long tbus; #endif typedef tbus thandle; typedef tbus tintptr; /* wide char, socket */ #if defined(_WIN32) typedef unsigned short twchar; typedef unsigned int tsock; typedef unsigned __int64 tui64; typedef signed __int64 tsi64; #else typedef int twchar; typedef int tsock; typedef unsigned long long tui64; typedef signed long long tsi64; #endif #endif xrdp-0.6.0/common/d3des.c000066400000000000000000000363531203155130500151350ustar00rootroot00000000000000/* * This is D3DES (V5.09) by Richard Outerbridge with the double and * triple-length support removed for use in VNC. Also the bytebit[] array * has been reversed so that the most significant bit in each byte of the * key is ignored, not the least significant. * * These changes are: * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. * * This software 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. */ /* D3DES (V5.09) - * * A portable, public domain, version of the Data Encryption Standard. * * Written with Symantec's THINK (Lightspeed) C by Richard Outerbridge. * Thanks to: Dan Hoey for his excellent Initial and Inverse permutation * code; Jim Gillogly & Phil Karn for the DES key schedule code; Dennis * Ferguson, Eric Young and Dana How for comparing notes; and Ray Lau, * for humouring me on. * * Copyright (c) 1988,1989,1990,1991,1992 by Richard Outerbridge. * (GEnie : OUTER; CIS : [71755,204]) Graven Imagery, 1992. */ #include "d3des.h" static void scrunch(unsigned char *, unsigned long *); static void unscrun(unsigned long *, unsigned char *); static void desfunc(unsigned long *, unsigned long *); static void cookey(unsigned long *); static unsigned long KnL[32] = { 0L }; /* static unsigned long KnR[32] = { 0L }; static unsigned long Kn3[32] = { 0L }; static unsigned char Df_Key[24] = { 0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef, 0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10, 0x89,0xab,0xcd,0xef,0x01,0x23,0x45,0x67 }; */ static unsigned short bytebit[8] = { 01, 02, 04, 010, 020, 040, 0100, 0200 }; static unsigned long bigbyte[24] = { 0x800000L, 0x400000L, 0x200000L, 0x100000L, 0x80000L, 0x40000L, 0x20000L, 0x10000L, 0x8000L, 0x4000L, 0x2000L, 0x1000L, 0x800L, 0x400L, 0x200L, 0x100L, 0x80L, 0x40L, 0x20L, 0x10L, 0x8L, 0x4L, 0x2L, 0x1L }; /* Use the key schedule specified in the Standard (ANSI X3.92-1981). */ static unsigned char pc1[56] = { 56, 48, 40, 32, 24, 16, 8, 0, 57, 49, 41, 33, 25, 17, 9, 1, 58, 50, 42, 34, 26, 18, 10, 2, 59, 51, 43, 35, 62, 54, 46, 38, 30, 22, 14, 6, 61, 53, 45, 37, 29, 21, 13, 5, 60, 52, 44, 36, 28, 20, 12, 4, 27, 19, 11, 3 }; static unsigned char totrot[16] = { 1,2,4,6,8,10,12,14,15,17,19,21,23,25,27,28 }; static unsigned char pc2[48] = { 13, 16, 10, 23, 0, 4, 2, 27, 14, 5, 20, 9, 22, 18, 11, 3, 25, 7, 15, 6, 26, 19, 12, 1, 40, 51, 30, 36, 46, 54, 29, 39, 50, 44, 32, 47, 43, 48, 38, 55, 33, 52, 45, 41, 49, 35, 28, 31 }; /* Thanks to James Gillogly & Phil Karn! */ void rfbDesKey(unsigned char *key, int edf) { register int i, j, l, m, n; unsigned char pc1m[56], pcr[56]; unsigned long kn[32]; for ( j = 0; j < 56; j++ ) { l = pc1[j]; m = l & 07; pc1m[j] = (key[l >> 3] & bytebit[m]) ? 1 : 0; } for( i = 0; i < 16; i++ ) { if( edf == DE1 ) m = (15 - i) << 1; else m = i << 1; n = m + 1; kn[m] = kn[n] = 0L; for( j = 0; j < 28; j++ ) { l = j + totrot[i]; if( l < 28 ) pcr[j] = pc1m[l]; else pcr[j] = pc1m[l - 28]; } for( j = 28; j < 56; j++ ) { l = j + totrot[i]; if( l < 56 ) pcr[j] = pc1m[l]; else pcr[j] = pc1m[l - 28]; } for( j = 0; j < 24; j++ ) { if( pcr[pc2[j]] ) kn[m] |= bigbyte[j]; if( pcr[pc2[j+24]] ) kn[n] |= bigbyte[j]; } } cookey(kn); return; } static void cookey(register unsigned long *raw1) { register unsigned long *cook, *raw0; unsigned long dough[32]; register int i; cook = dough; for( i = 0; i < 16; i++, raw1++ ) { raw0 = raw1++; *cook = (*raw0 & 0x00fc0000L) << 6; *cook |= (*raw0 & 0x00000fc0L) << 10; *cook |= (*raw1 & 0x00fc0000L) >> 10; *cook++ |= (*raw1 & 0x00000fc0L) >> 6; *cook = (*raw0 & 0x0003f000L) << 12; *cook |= (*raw0 & 0x0000003fL) << 16; *cook |= (*raw1 & 0x0003f000L) >> 4; *cook++ |= (*raw1 & 0x0000003fL); } rfbUseKey(dough); return; } void rfbCPKey(register unsigned long *into) { register unsigned long *from, *endp; from = KnL, endp = &KnL[32]; while( from < endp ) *into++ = *from++; return; } void rfbUseKey(register unsigned long *from) { register unsigned long *to, *endp; to = KnL, endp = &KnL[32]; while( to < endp ) *to++ = *from++; return; } void rfbDes(unsigned char *inblock, unsigned char *outblock) { unsigned long work[2]; scrunch(inblock, work); desfunc(work, KnL); unscrun(work, outblock); return; } static void scrunch(register unsigned char *outof, register unsigned long *into) { *into = (*outof++ & 0xffL) << 24; *into |= (*outof++ & 0xffL) << 16; *into |= (*outof++ & 0xffL) << 8; *into++ |= (*outof++ & 0xffL); *into = (*outof++ & 0xffL) << 24; *into |= (*outof++ & 0xffL) << 16; *into |= (*outof++ & 0xffL) << 8; *into |= (*outof & 0xffL); return; } static void unscrun(register unsigned long *outof, register unsigned char *into) { *into++ = (unsigned char)((*outof >> 24) & 0xffL); *into++ = (unsigned char)((*outof >> 16) & 0xffL); *into++ = (unsigned char)((*outof >> 8) & 0xffL); *into++ = (unsigned char)( *outof++ & 0xffL); *into++ = (unsigned char)((*outof >> 24) & 0xffL); *into++ = (unsigned char)((*outof >> 16) & 0xffL); *into++ = (unsigned char)((*outof >> 8) & 0xffL); *into = (unsigned char)( *outof & 0xffL); return; } static unsigned long SP1[64] = { 0x01010400L, 0x00000000L, 0x00010000L, 0x01010404L, 0x01010004L, 0x00010404L, 0x00000004L, 0x00010000L, 0x00000400L, 0x01010400L, 0x01010404L, 0x00000400L, 0x01000404L, 0x01010004L, 0x01000000L, 0x00000004L, 0x00000404L, 0x01000400L, 0x01000400L, 0x00010400L, 0x00010400L, 0x01010000L, 0x01010000L, 0x01000404L, 0x00010004L, 0x01000004L, 0x01000004L, 0x00010004L, 0x00000000L, 0x00000404L, 0x00010404L, 0x01000000L, 0x00010000L, 0x01010404L, 0x00000004L, 0x01010000L, 0x01010400L, 0x01000000L, 0x01000000L, 0x00000400L, 0x01010004L, 0x00010000L, 0x00010400L, 0x01000004L, 0x00000400L, 0x00000004L, 0x01000404L, 0x00010404L, 0x01010404L, 0x00010004L, 0x01010000L, 0x01000404L, 0x01000004L, 0x00000404L, 0x00010404L, 0x01010400L, 0x00000404L, 0x01000400L, 0x01000400L, 0x00000000L, 0x00010004L, 0x00010400L, 0x00000000L, 0x01010004L }; static unsigned long SP2[64] = { 0x80108020L, 0x80008000L, 0x00008000L, 0x00108020L, 0x00100000L, 0x00000020L, 0x80100020L, 0x80008020L, 0x80000020L, 0x80108020L, 0x80108000L, 0x80000000L, 0x80008000L, 0x00100000L, 0x00000020L, 0x80100020L, 0x00108000L, 0x00100020L, 0x80008020L, 0x00000000L, 0x80000000L, 0x00008000L, 0x00108020L, 0x80100000L, 0x00100020L, 0x80000020L, 0x00000000L, 0x00108000L, 0x00008020L, 0x80108000L, 0x80100000L, 0x00008020L, 0x00000000L, 0x00108020L, 0x80100020L, 0x00100000L, 0x80008020L, 0x80100000L, 0x80108000L, 0x00008000L, 0x80100000L, 0x80008000L, 0x00000020L, 0x80108020L, 0x00108020L, 0x00000020L, 0x00008000L, 0x80000000L, 0x00008020L, 0x80108000L, 0x00100000L, 0x80000020L, 0x00100020L, 0x80008020L, 0x80000020L, 0x00100020L, 0x00108000L, 0x00000000L, 0x80008000L, 0x00008020L, 0x80000000L, 0x80100020L, 0x80108020L, 0x00108000L }; static unsigned long SP3[64] = { 0x00000208L, 0x08020200L, 0x00000000L, 0x08020008L, 0x08000200L, 0x00000000L, 0x00020208L, 0x08000200L, 0x00020008L, 0x08000008L, 0x08000008L, 0x00020000L, 0x08020208L, 0x00020008L, 0x08020000L, 0x00000208L, 0x08000000L, 0x00000008L, 0x08020200L, 0x00000200L, 0x00020200L, 0x08020000L, 0x08020008L, 0x00020208L, 0x08000208L, 0x00020200L, 0x00020000L, 0x08000208L, 0x00000008L, 0x08020208L, 0x00000200L, 0x08000000L, 0x08020200L, 0x08000000L, 0x00020008L, 0x00000208L, 0x00020000L, 0x08020200L, 0x08000200L, 0x00000000L, 0x00000200L, 0x00020008L, 0x08020208L, 0x08000200L, 0x08000008L, 0x00000200L, 0x00000000L, 0x08020008L, 0x08000208L, 0x00020000L, 0x08000000L, 0x08020208L, 0x00000008L, 0x00020208L, 0x00020200L, 0x08000008L, 0x08020000L, 0x08000208L, 0x00000208L, 0x08020000L, 0x00020208L, 0x00000008L, 0x08020008L, 0x00020200L }; static unsigned long SP4[64] = { 0x00802001L, 0x00002081L, 0x00002081L, 0x00000080L, 0x00802080L, 0x00800081L, 0x00800001L, 0x00002001L, 0x00000000L, 0x00802000L, 0x00802000L, 0x00802081L, 0x00000081L, 0x00000000L, 0x00800080L, 0x00800001L, 0x00000001L, 0x00002000L, 0x00800000L, 0x00802001L, 0x00000080L, 0x00800000L, 0x00002001L, 0x00002080L, 0x00800081L, 0x00000001L, 0x00002080L, 0x00800080L, 0x00002000L, 0x00802080L, 0x00802081L, 0x00000081L, 0x00800080L, 0x00800001L, 0x00802000L, 0x00802081L, 0x00000081L, 0x00000000L, 0x00000000L, 0x00802000L, 0x00002080L, 0x00800080L, 0x00800081L, 0x00000001L, 0x00802001L, 0x00002081L, 0x00002081L, 0x00000080L, 0x00802081L, 0x00000081L, 0x00000001L, 0x00002000L, 0x00800001L, 0x00002001L, 0x00802080L, 0x00800081L, 0x00002001L, 0x00002080L, 0x00800000L, 0x00802001L, 0x00000080L, 0x00800000L, 0x00002000L, 0x00802080L }; static unsigned long SP5[64] = { 0x00000100L, 0x02080100L, 0x02080000L, 0x42000100L, 0x00080000L, 0x00000100L, 0x40000000L, 0x02080000L, 0x40080100L, 0x00080000L, 0x02000100L, 0x40080100L, 0x42000100L, 0x42080000L, 0x00080100L, 0x40000000L, 0x02000000L, 0x40080000L, 0x40080000L, 0x00000000L, 0x40000100L, 0x42080100L, 0x42080100L, 0x02000100L, 0x42080000L, 0x40000100L, 0x00000000L, 0x42000000L, 0x02080100L, 0x02000000L, 0x42000000L, 0x00080100L, 0x00080000L, 0x42000100L, 0x00000100L, 0x02000000L, 0x40000000L, 0x02080000L, 0x42000100L, 0x40080100L, 0x02000100L, 0x40000000L, 0x42080000L, 0x02080100L, 0x40080100L, 0x00000100L, 0x02000000L, 0x42080000L, 0x42080100L, 0x00080100L, 0x42000000L, 0x42080100L, 0x02080000L, 0x00000000L, 0x40080000L, 0x42000000L, 0x00080100L, 0x02000100L, 0x40000100L, 0x00080000L, 0x00000000L, 0x40080000L, 0x02080100L, 0x40000100L }; static unsigned long SP6[64] = { 0x20000010L, 0x20400000L, 0x00004000L, 0x20404010L, 0x20400000L, 0x00000010L, 0x20404010L, 0x00400000L, 0x20004000L, 0x00404010L, 0x00400000L, 0x20000010L, 0x00400010L, 0x20004000L, 0x20000000L, 0x00004010L, 0x00000000L, 0x00400010L, 0x20004010L, 0x00004000L, 0x00404000L, 0x20004010L, 0x00000010L, 0x20400010L, 0x20400010L, 0x00000000L, 0x00404010L, 0x20404000L, 0x00004010L, 0x00404000L, 0x20404000L, 0x20000000L, 0x20004000L, 0x00000010L, 0x20400010L, 0x00404000L, 0x20404010L, 0x00400000L, 0x00004010L, 0x20000010L, 0x00400000L, 0x20004000L, 0x20000000L, 0x00004010L, 0x20000010L, 0x20404010L, 0x00404000L, 0x20400000L, 0x00404010L, 0x20404000L, 0x00000000L, 0x20400010L, 0x00000010L, 0x00004000L, 0x20400000L, 0x00404010L, 0x00004000L, 0x00400010L, 0x20004010L, 0x00000000L, 0x20404000L, 0x20000000L, 0x00400010L, 0x20004010L }; static unsigned long SP7[64] = { 0x00200000L, 0x04200002L, 0x04000802L, 0x00000000L, 0x00000800L, 0x04000802L, 0x00200802L, 0x04200800L, 0x04200802L, 0x00200000L, 0x00000000L, 0x04000002L, 0x00000002L, 0x04000000L, 0x04200002L, 0x00000802L, 0x04000800L, 0x00200802L, 0x00200002L, 0x04000800L, 0x04000002L, 0x04200000L, 0x04200800L, 0x00200002L, 0x04200000L, 0x00000800L, 0x00000802L, 0x04200802L, 0x00200800L, 0x00000002L, 0x04000000L, 0x00200800L, 0x04000000L, 0x00200800L, 0x00200000L, 0x04000802L, 0x04000802L, 0x04200002L, 0x04200002L, 0x00000002L, 0x00200002L, 0x04000000L, 0x04000800L, 0x00200000L, 0x04200800L, 0x00000802L, 0x00200802L, 0x04200800L, 0x00000802L, 0x04000002L, 0x04200802L, 0x04200000L, 0x00200800L, 0x00000000L, 0x00000002L, 0x04200802L, 0x00000000L, 0x00200802L, 0x04200000L, 0x00000800L, 0x04000002L, 0x04000800L, 0x00000800L, 0x00200002L }; static unsigned long SP8[64] = { 0x10001040L, 0x00001000L, 0x00040000L, 0x10041040L, 0x10000000L, 0x10001040L, 0x00000040L, 0x10000000L, 0x00040040L, 0x10040000L, 0x10041040L, 0x00041000L, 0x10041000L, 0x00041040L, 0x00001000L, 0x00000040L, 0x10040000L, 0x10000040L, 0x10001000L, 0x00001040L, 0x00041000L, 0x00040040L, 0x10040040L, 0x10041000L, 0x00001040L, 0x00000000L, 0x00000000L, 0x10040040L, 0x10000040L, 0x10001000L, 0x00041040L, 0x00040000L, 0x00041040L, 0x00040000L, 0x10041000L, 0x00001000L, 0x00000040L, 0x10040040L, 0x00001000L, 0x00041040L, 0x10001000L, 0x00000040L, 0x10000040L, 0x10040000L, 0x10040040L, 0x10000000L, 0x00040000L, 0x10001040L, 0x00000000L, 0x10041040L, 0x00040040L, 0x10000040L, 0x10040000L, 0x10001000L, 0x10001040L, 0x00000000L, 0x10041040L, 0x00041000L, 0x00041000L, 0x00001040L, 0x00001040L, 0x00040040L, 0x10000000L, 0x10041000L }; static void desfunc(register unsigned long* block, register unsigned long *keys) { register unsigned long fval, work, right, leftt; register int round; leftt = block[0]; right = block[1]; work = ((leftt >> 4) ^ right) & 0x0f0f0f0fL; right ^= work; leftt ^= (work << 4); work = ((leftt >> 16) ^ right) & 0x0000ffffL; right ^= work; leftt ^= (work << 16); work = ((right >> 2) ^ leftt) & 0x33333333L; leftt ^= work; right ^= (work << 2); work = ((right >> 8) ^ leftt) & 0x00ff00ffL; leftt ^= work; right ^= (work << 8); right = ((right << 1) | ((right >> 31) & 1L)) & 0xffffffffL; work = (leftt ^ right) & 0xaaaaaaaaL; leftt ^= work; right ^= work; leftt = ((leftt << 1) | ((leftt >> 31) & 1L)) & 0xffffffffL; for( round = 0; round < 8; round++ ) { work = (right << 28) | (right >> 4); work ^= *keys++; fval = SP7[ work & 0x3fL]; fval |= SP5[(work >> 8) & 0x3fL]; fval |= SP3[(work >> 16) & 0x3fL]; fval |= SP1[(work >> 24) & 0x3fL]; work = right ^ *keys++; fval |= SP8[ work & 0x3fL]; fval |= SP6[(work >> 8) & 0x3fL]; fval |= SP4[(work >> 16) & 0x3fL]; fval |= SP2[(work >> 24) & 0x3fL]; leftt ^= fval; work = (leftt << 28) | (leftt >> 4); work ^= *keys++; fval = SP7[ work & 0x3fL]; fval |= SP5[(work >> 8) & 0x3fL]; fval |= SP3[(work >> 16) & 0x3fL]; fval |= SP1[(work >> 24) & 0x3fL]; work = leftt ^ *keys++; fval |= SP8[ work & 0x3fL]; fval |= SP6[(work >> 8) & 0x3fL]; fval |= SP4[(work >> 16) & 0x3fL]; fval |= SP2[(work >> 24) & 0x3fL]; right ^= fval; } right = (right << 31) | (right >> 1); work = (leftt ^ right) & 0xaaaaaaaaL; leftt ^= work; right ^= work; leftt = (leftt << 31) | (leftt >> 1); work = ((leftt >> 8) ^ right) & 0x00ff00ffL; right ^= work; leftt ^= (work << 8); work = ((leftt >> 2) ^ right) & 0x33333333L; right ^= work; leftt ^= (work << 2); work = ((right >> 16) ^ leftt) & 0x0000ffffL; leftt ^= work; right ^= (work << 16); work = ((right >> 4) ^ leftt) & 0x0f0f0f0fL; leftt ^= work; right ^= (work << 4); *block++ = right; *block = leftt; return; } /* Validation sets: * * Single-length key, single-length plaintext - * Key : 0123 4567 89ab cdef * Plain : 0123 4567 89ab cde7 * Cipher : c957 4425 6a5e d31d * * Double-length key, single-length plaintext - * Key : 0123 4567 89ab cdef fedc ba98 7654 3210 * Plain : 0123 4567 89ab cde7 * Cipher : 7f1d 0a77 826b 8aff * * Double-length key, double-length plaintext - * Key : 0123 4567 89ab cdef fedc ba98 7654 3210 * Plain : 0123 4567 89ab cdef 0123 4567 89ab cdff * Cipher : 27a0 8440 406a df60 278f 47cf 42d6 15d7 * * Triple-length key, single-length plaintext - * Key : 0123 4567 89ab cdef fedc ba98 7654 3210 89ab cdef 0123 4567 * Plain : 0123 4567 89ab cde7 * Cipher : de0b 7c06 ae5e 0ed5 * * Triple-length key, double-length plaintext - * Key : 0123 4567 89ab cdef fedc ba98 7654 3210 89ab cdef 0123 4567 * Plain : 0123 4567 89ab cdef 0123 4567 89ab cdff * Cipher : ad0d 1b30 ac17 cf07 0ed1 1c63 81e4 4de5 * * d3des V5.0a rwo 9208.07 18:44 Graven Imagery **********************************************************************/ xrdp-0.6.0/common/d3des.h000066400000000000000000000032071203155130500151320ustar00rootroot00000000000000#ifndef D3DES_H #define D3DES_H /* * This is D3DES (V5.09) by Richard Outerbridge with the double and * triple-length support removed for use in VNC. * * These changes are: * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. * * This software 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. */ /* d3des.h - * * Headers and defines for d3des.c * Graven Imagery, 1992. * * Copyright (c) 1988,1989,1990,1991,1992 by Richard Outerbridge * (GEnie : OUTER; CIS : [71755,204]) */ #define EN0 0 /* MODE == encrypt */ #define DE1 1 /* MODE == decrypt */ extern void rfbDesKey(unsigned char *, int); /* hexkey[8] MODE * Sets the internal key register according to the hexadecimal * key contained in the 8 bytes of hexkey, according to the DES, * for encryption or decryption according to MODE. */ extern void rfbUseKey(unsigned long *); /* cookedkey[32] * Loads the internal key register with the data in cookedkey. */ extern void rfbCPKey(unsigned long *); /* cookedkey[32] * Copies the contents of the internal key register into the storage * located at &cookedkey[0]. */ extern void rfbDes(unsigned char *, unsigned char *); /* from[8] to[8] * Encrypts/Decrypts (according to the key currently loaded in the * internal key register) one block of eight bytes at address 'from' * into the block at address 'to'. They can be the same. */ /* d3des.h V5.09 rwo 9208.04 15:06 Graven Imagery ********************************************************************/ #endif xrdp-0.6.0/common/defines.h000066400000000000000000000070061203155130500155460ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2004-2009 main define/macro file */ #ifndef DEFINES_H #define DEFINES_H /* check for debug */ #ifdef XRDP_DEBUG #define DEBUG(args) g_writeln args; #define LIB_DEBUG(_mod, _text) _mod->server_msg(_mod, _text, 1); #else #define DEBUG(args) #define LIB_DEBUG(_mod, _text) #endif /* other macros */ #undef MIN #define MIN(x1, x2) ((x1) < (x2) ? (x1) : (x2)) #undef MAX #define MAX(x1, x2) ((x1) > (x2) ? (x1) : (x2)) #undef HIWORD #define HIWORD(in) (((in) & 0xffff0000) >> 16) #undef LOWORD #define LOWORD(in) ((in) & 0x0000ffff) #undef MAKELONG #define MAKELONG(lo, hi) ((((hi) & 0xffff) << 16) | ((lo) & 0xffff)) #define MAKERECT(r, x, y, cx, cy) \ { (r).left = x; (r).top = y; (r).right = (x) + (cx); (r).bottom = (y) + (cy); } #define ISRECTEMPTY(r) (((r).right <= (r).left) || ((r).bottom <= (r).top)) #define RECTOFFSET(r, dx, dy) \ { (r).left += dx; (r).top += dy; (r).right += dx; (r).bottom += dy; } #define GETPIXEL8(d, x, y, w) (*(((unsigned char*)d) + ((y) * (w) + (x)))) #define GETPIXEL16(d, x, y, w) (*(((unsigned short*)d) + ((y) * (w) + (x)))) #define GETPIXEL32(d, x, y, w) (*(((unsigned int*)d) + ((y) * (w) + (x)))) #define SETPIXEL8(d, x, y, w, v) \ (*(((unsigned char*)d) + ((y) * (w) + (x))) = (v)) #define SETPIXEL16(d, x, y, w, v) \ (*(((unsigned short*)d) + ((y) * (w) + (x))) = (v)) #define SETPIXEL32(d, x, y, w, v) \ (*(((unsigned int*)d) + ((y) * (w) + (x))) = (v)) #define COLOR8(r, g, b) \ ( \ (((r) >> 5) << 0) | \ (((g) >> 5) << 3) | \ (((b) >> 6) << 6) \ ) #define COLOR15(r, g, b) ((((r) >> 3) << 10) | (((g) >> 3) << 5) | ((b) >> 3)) #define COLOR16(r, g, b) ((((r) >> 3) << 11) | (((g) >> 2) << 5) | ((b) >> 3)) #define COLOR24RGB(r, g, b) (((r) << 16) | ((g) << 8) | (b)) #define COLOR24BGR(r, g, b) (((b) << 16) | ((g) << 8) | (r)) #define HRED(c) ((c & 0xff0000) >> 16) #define HGREEN(c) ((c & 0x00ff00) >> 8) #define HBLUE(c) ((c & 0x0000ff)) #define HCOLOR(bpp,c) \ ( \ (bpp==8?COLOR8(HRED(c),HGREEN(c),HBLUE(c)): \ (bpp==15?COLOR15(HRED(c),HGREEN(c),HBLUE(c)): \ (bpp==16?COLOR16(HRED(c),HGREEN(c),HBLUE(c)): \ (bpp==24?COLOR24BGR(HRED(c),HGREEN(c),HBLUE(c)):c) \ ) \ ) \ ) \ ) #define SPLITCOLOR15(r, g, b, c) \ { \ r = (((c) >> 7) & 0xf8) | (((c) >> 12) & 0x7); \ g = (((c) >> 2) & 0xf8) | (((c) >> 8) & 0x7); \ b = (((c) << 3) & 0xf8) | (((c) >> 2) & 0x7); \ } #define SPLITCOLOR16(r, g, b, c) \ { \ r = (((c) >> 8) & 0xf8) | (((c) >> 13) & 0x7); \ g = (((c) >> 3) & 0xfc) | (((c) >> 9) & 0x3); \ b = (((c) << 3) & 0xf8) | (((c) >> 2) & 0x7); \ } #define SPLITCOLOR32(r, g, b, c) \ { \ r = ((c) >> 16) & 0xff; \ g = ((c) >> 8) & 0xff; \ b = (c) & 0xff; \ } /* font macros */ #define FONT_DATASIZE(f) \ ((((f)->height * (((f)->width + 7) / 8)) + 3) & ~3); /* use crc for bitmap cache lookups */ #define USE_CRC #endif xrdp-0.6.0/common/file.c000066400000000000000000000164461203155130500150530ustar00rootroot00000000000000/* Copyright (c) 2004-2010 Jay Sorg Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. read a config file */ #include "arch.h" #include "os_calls.h" #include "list.h" #include "file.h" #include "parse.h" /*****************************************************************************/ /* returns error returns 0 if everything is ok returns 1 if problem reading file */ static int APP_CC l_file_read_sections(int fd, int max_file_size, struct list* names) { struct stream* s; char text[256]; char c; int in_it; int in_it_index; int len; int index; int rv; rv = 0; g_file_seek(fd, 0); in_it_index = 0; in_it = 0; g_memset(text, 0, 256); list_clear(names); make_stream(s); init_stream(s, max_file_size); len = g_file_read(fd, s->data, max_file_size); if (len > 0) { s->end = s->p + len; for (index = 0; index < len; index++) { in_uint8(s, c); if (c == '[') { in_it = 1; } else if (c == ']') { list_add_item(names, (tbus)g_strdup(text)); in_it = 0; in_it_index = 0; g_memset(text, 0, 256); } else if (in_it) { text[in_it_index] = c; in_it_index++; } } } else if (len < 0) { rv = 1; } free_stream(s); return rv; } /*****************************************************************************/ static int APP_CC file_read_line(struct stream* s, char* text) { int i; int skip_to_end; int at_end; char c; char* hold; skip_to_end = 0; if (!s_check_rem(s, 1)) { return 1; } hold = s->p; i = 0; in_uint8(s, c); while (c != 10 && c != 13) { if (c == '#' || c == '!' || c == ';') { skip_to_end = 1; } if (!skip_to_end) { text[i] = c; i++; } if (s_check_rem(s, 1)) { in_uint8(s, c); } else { c = 0; break; } } if (c == 10 || c == 13) { at_end = 0; while (c == 10 || c == 13) { if (s_check_rem(s, 1)) { in_uint8(s, c); } else { at_end = 1; break; } } if (!at_end) { s->p--; } } text[i] = 0; if (text[0] == '[') { s->p = hold; return 1; } return 0; } /*****************************************************************************/ /* returns error */ static int APP_CC file_split_name_value(char* text, char* name, char* value) { int len; int i; int value_index; int name_index; int on_to; value_index = 0; name_index = 0; on_to = 0; name[0] = 0; value[0] = 0; len = g_strlen(text); for (i = 0; i < len; i++) { if (text[i] == '=') { on_to = 1; } else if (on_to) { value[value_index] = text[i]; value_index++; value[value_index] = 0; } else { name[name_index] = text[i]; name_index++; name[name_index] = 0; } } g_strtrim(name, 3); /* trim both right and left */ g_strtrim(value, 3); /* trim both right and left */ return 0; } /*****************************************************************************/ /* return error */ static int APP_CC l_file_read_section(int fd, int max_file_size, const char* section, struct list* names, struct list* values) { struct stream* s; char text[512]; char name[512]; char value[512]; char c; int in_it; int in_it_index; int len; int index; int file_size; file_size = 32 * 1024; /* 32 K file size limit */ g_file_seek(fd, 0); in_it_index = 0; in_it = 0; g_memset(text, 0, 512); list_clear(names); list_clear(values); make_stream(s); init_stream(s, file_size); len = g_file_read(fd, s->data, file_size); if (len > 0) { s->end = s->p + len; for (index = 0; index < len; index++) { in_uint8(s, c); if (c == '[') { in_it = 1; } else if (c == ']') { if (g_strcasecmp(section, text) == 0) { file_read_line(s, text); while (file_read_line(s, text) == 0) { if (g_strlen(text) > 0) { file_split_name_value(text, name, value); list_add_item(names, (tbus)g_strdup(name)); list_add_item(values, (tbus)g_strdup(value)); } } free_stream(s); return 0; } in_it = 0; in_it_index = 0; g_memset(text, 0, 512); } else if (in_it) { text[in_it_index] = c; in_it_index++; } } } free_stream(s); return 1; } /*****************************************************************************/ /* returns error returns 0 if everything is ok returns 1 if problem reading file */ /* 32 K file size limit */ int APP_CC file_read_sections(int fd, struct list* names) { return l_file_read_sections(fd, 32 * 1024, names); } /*****************************************************************************/ /* return error */ /* this function should be prefered over file_read_sections because it can read any file size */ int APP_CC file_by_name_read_sections(const char* file_name, struct list* names) { int fd; int file_size; int rv; file_size = g_file_get_size(file_name); if (file_size < 1) { return 1; } fd = g_file_open(file_name); if (fd < 1) { return 1; } rv = l_file_read_sections(fd, file_size, names); g_file_close(fd); return rv; } /*****************************************************************************/ /* return error */ /* 32 K file size limit */ int APP_CC file_read_section(int fd, const char* section, struct list* names, struct list* values) { return l_file_read_section(fd, 32 * 1024, section, names, values); } /*****************************************************************************/ /* return error */ /* this function should be prefered over file_read_section because it can read any file size */ int APP_CC file_by_name_read_section(const char* file_name, const char* section, struct list* names, struct list* values) { int fd; int file_size; int rv; file_size = g_file_get_size(file_name); if (file_size < 1) { return 1; } fd = g_file_open(file_name); if (fd < 1) { return 1; } rv = l_file_read_section(fd, file_size, section, names, values); g_file_close(fd); return rv; } xrdp-0.6.0/common/file.h000066400000000000000000000031071203155130500150460ustar00rootroot00000000000000/* Copyright (c) 2004-2010 Jay Sorg Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. read a config file */ #if !defined(FILE_H) #define FILE_H #include "arch.h" int APP_CC file_read_sections(int fd, struct list* names); int APP_CC file_by_name_read_sections(const char* file_name, struct list* names); int APP_CC file_read_section(int fd, const char* section, struct list* names, struct list* values); int APP_CC file_by_name_read_section(const char* file_name, const char* section, struct list* names, struct list* values); #endif xrdp-0.6.0/common/file_loc.h000066400000000000000000000022401203155130500157000ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2004-2010 default file locations for log, config, etc */ #if !defined(FILE_LOC_H) #define FILE_LOC_H #if !defined(XRDP_CFG_PATH) #define XRDP_CFG_PATH "/etc/xrdp" #endif #if !defined(XRDP_PID_PATH) #define XRDP_PID_PATH "/var/run" #endif #if !defined(XRDP_SBIN_PATH) #define XRDP_SBIN_PATH "/usr/local/sbin" #endif #if !defined(XRDP_SHARE_PATH) #define XRDP_SHARE_PATH "/usr/local/share/xrdp" #endif #endif xrdp-0.6.0/common/list.c000066400000000000000000000123041203155130500150740ustar00rootroot00000000000000/* Copyright (c) 2004-2010 Jay Sorg Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. simple list */ #include "arch.h" #include "os_calls.h" #include "list.h" /*****************************************************************************/ struct list* APP_CC list_create(void) { struct list* self; self = (struct list*)g_malloc(sizeof(struct list), 1); self->grow_by = 10; self->alloc_size = 10; self->items = (tbus*)g_malloc(sizeof(tbus) * 10, 1); return self; } /*****************************************************************************/ void APP_CC list_delete(struct list* self) { int i; if (self == 0) { return; } if (self->auto_free) { for (i = 0; i < self->count; i++) { g_free((void*)self->items[i]); self->items[i] = 0; } } g_free(self->items); g_free(self); } /*****************************************************************************/ void APP_CC list_add_item(struct list* self, tbus item) { tbus* p; int i; if (self->count >= self->alloc_size) { i = self->alloc_size; self->alloc_size += self->grow_by; p = (tbus*)g_malloc(sizeof(tbus) * self->alloc_size, 1); g_memcpy(p, self->items, sizeof(tbus) * i); g_free(self->items); self->items = p; } self->items[self->count] = item; self->count++; } /*****************************************************************************/ tbus APP_CC list_get_item(struct list* self, int index) { if (index < 0 || index >= self->count) { return 0; } return self->items[index]; } /*****************************************************************************/ void APP_CC list_clear(struct list* self) { int i; if (self->auto_free) { for (i = 0; i < self->count; i++) { g_free((void*)self->items[i]); self->items[i] = 0; } } g_free(self->items); self->count = 0; self->grow_by = 10; self->alloc_size = 10; self->items = (tbus*)g_malloc(sizeof(tbus) * 10, 1); } /*****************************************************************************/ int APP_CC list_index_of(struct list* self, tbus item) { int i; for (i = 0; i < self->count; i++) { if (self->items[i] == item) { return i; } } return -1; } /*****************************************************************************/ void APP_CC list_remove_item(struct list* self, int index) { int i; if (index >= 0 && index < self->count) { if (self->auto_free) { g_free((void*)self->items[index]); self->items[index] = 0; } for (i = index; i < (self->count - 1); i++) { self->items[i] = self->items[i + 1]; } self->count--; } } /*****************************************************************************/ void APP_CC list_insert_item(struct list* self, int index, tbus item) { tbus* p; int i; if (index == self->count) { list_add_item(self, item); return; } if (index >= 0 && index < self->count) { self->count++; if (self->count > self->alloc_size) { i = self->alloc_size; self->alloc_size += self->grow_by; p = (tbus*)g_malloc(sizeof(tbus) * self->alloc_size, 1); g_memcpy(p, self->items, sizeof(tbus) * i); g_free(self->items); self->items = p; } for (i = (self->count - 2); i >= index; i--) { self->items[i + 1] = self->items[i]; } self->items[index] = item; } } /*****************************************************************************/ /* append one list to another using strdup for each item in the list */ /* begins copy at start_index, a zero based index on the soure list */ void APP_CC list_append_list_strdup(struct list* self, struct list* dest, int start_index) { int index; tbus item; char* dup; for (index = start_index; index < self->count; index++) { item = list_get_item(self, index); dup = g_strdup((char*)item); list_add_item(dest, (tbus)dup); } } /*****************************************************************************/ void APP_CC list_dump_items(struct list* self) { int index; tbus item; if (self->count == 0) { g_writeln("List is empty"); } for (index = 0; index < self->count; index++) { g_writeln("%d: %s", index, list_get_item(self, index)); } } xrdp-0.6.0/common/list.h000066400000000000000000000035121203155130500151020ustar00rootroot00000000000000/* Copyright (c) 2004-2010 Jay Sorg Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. simple list */ #if !defined(LIST_H) #define LIST_H #include "arch.h" /* list */ struct list { tbus* items; int count; int alloc_size; int grow_by; int auto_free; }; struct list* APP_CC list_create(void); void APP_CC list_delete(struct list* self); void APP_CC list_add_item(struct list* self, tbus item); tbus APP_CC list_get_item(struct list* self, int index); void APP_CC list_clear(struct list* self); int APP_CC list_index_of(struct list* self, tbus item); void APP_CC list_remove_item(struct list* self, int index); void APP_CC list_insert_item(struct list* self, int index, tbus item); void APP_CC list_append_list_strdup(struct list* self, struct list* dest, int start_index); void APP_CC list_dump_items(struct list* self); #endif xrdp-0.6.0/common/log.c000066400000000000000000000147201203155130500147060ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2005-2010 */ #include #include #include #include #include #include #include #include "os_calls.h" #include "log.h" /** * * @brief Opens log file * @param fname log file name * @return see open(2) return values * */ static int DEFAULT_CC log_file_open(const char* fname) { return open(fname, O_WRONLY | O_CREAT | O_APPEND | O_SYNC, S_IRUSR | S_IWUSR); } /** * * @brief Converts xrdp log level to syslog logging level * @param xrdp logging level * @return syslog equivalent logging level * */ static int DEFAULT_CC log_xrdp2syslog(const int lvl) { switch (lvl) { case LOG_LEVEL_ALWAYS: return LOG_CRIT; case LOG_LEVEL_ERROR: return LOG_ERR; case LOG_LEVEL_WARNING: return LOG_WARNING; case LOG_LEVEL_INFO: return LOG_INFO; /* case LOG_LEVEL_DEBUG: */ default: return LOG_DEBUG; } } /** *ring * @brief Converts xrdp log level to syslog logging level * @param lvl logging level * @param str pointer to a st * @return syslog equivalent logging level * */ static void DEFAULT_CC log_lvl2str(int lvl, char* str) { switch (lvl) { case LOG_LEVEL_ALWAYS: snprintf(str, 9, "%s", "[CORE ] "); break; case LOG_LEVEL_ERROR: snprintf(str, 9, "%s", "[ERROR] "); break; case LOG_LEVEL_WARNING: snprintf(str, 9, "%s", "[WARN ] "); break; case LOG_LEVEL_INFO: snprintf(str, 9, "%s", "[INFO ] "); break; /* case LOG_LEVEL_DEBUG: */ default: snprintf(str, 9, "%s", "[DEBUG] "); break; } } /******************************************************************************/ int DEFAULT_CC log_message(struct log_config* l_cfg, const unsigned int lvl, const char* msg, ...) { char buff[LOG_BUFFER_SIZE + 31]; /* 19 (datetime) 4 (space+cr+lf+\0) */ va_list ap; int len = 0; int rv; time_t now_t; struct tm* now; rv = 0; if (0 == l_cfg) { return LOG_ERROR_NO_CFG; } if (0 > l_cfg->fd) { return LOG_ERROR_FILE_NOT_OPEN; } now_t = time(&now_t); now = localtime(&now_t); snprintf(buff, 21, "[%.4d%.2d%.2d-%.2d:%.2d:%.2d] ", (now->tm_year) + 1900, (now->tm_mon) + 1, now->tm_mday, now->tm_hour, now->tm_min, now->tm_sec); log_lvl2str(lvl, buff + 20); va_start(ap, msg); len = vsnprintf(buff + 28, LOG_BUFFER_SIZE, msg, ap); va_end(ap); /* checking for truncated messages */ if (len > LOG_BUFFER_SIZE) { log_message(l_cfg, LOG_LEVEL_WARNING, "next message will be truncated"); } /* forcing the end of message string */ #ifdef _WIN32 buff[len + 28] = '\r'; buff[len + 29] = '\n'; buff[len + 30] = '\0'; #else #ifdef _MACOS buff[len + 28] = '\r'; buff[len + 29] = '\0'; #else buff[len + 28] = '\n'; buff[len + 29] = '\0'; #endif #endif if (l_cfg->enable_syslog && (lvl <= l_cfg->log_level)) { /* log to syslog */ syslog(log_xrdp2syslog(lvl), buff + 20); } if (lvl <= l_cfg->log_level) { /* log to console */ g_printf((char*)buff); /* log to application logfile */ #ifdef LOG_ENABLE_THREAD pthread_mutex_lock(&(l_cfg->log_lock)); #endif rv = g_file_write(l_cfg->fd, (char*)buff, g_strlen((char*)buff)); #ifdef LOG_ENABLE_THREAD pthread_mutex_unlock(&(l_cfg->log_lock)); #endif } return rv; } /******************************************************************************/ int DEFAULT_CC log_start(struct log_config* l_cfg) { if (0 == l_cfg) { return LOG_ERROR_MALLOC; } /* if logfile is NULL, we use a default logfile */ if (0 == l_cfg->log_file) { l_cfg->log_file = g_strdup("./myprogram.log"); } /* if progname is NULL, we use a default name */ if (0 == l_cfg->program_name) { l_cfg->program_name = g_strdup("myprogram"); } /* open file */ l_cfg->fd = log_file_open(l_cfg->log_file); if (-1 == l_cfg->fd) { return LOG_ERROR_FILE_OPEN; } /* if syslog is enabled, open it */ if (l_cfg->enable_syslog) { openlog(l_cfg->program_name, LOG_CONS | LOG_PID, LOG_DAEMON); } #ifdef LOG_ENABLE_THREAD pthread_mutexattr_init(&(l_cfg->log_lock_attr)); pthread_mutex_init(&(l_cfg->log_lock), &(l_cfg->log_lock_attr)); #endif return LOG_STARTUP_OK; } /******************************************************************************/ void DEFAULT_CC log_end(struct log_config* l_cfg) { /* if log is closed, quit silently */ if (0 == l_cfg) { return; } /* closing log file */ log_message(l_cfg, LOG_LEVEL_ALWAYS, "shutting down log subsystem..."); if (0 > l_cfg->fd) { /* if syslog is enabled, close it */ if (l_cfg->enable_syslog) { closelog(); } } /* closing logfile... */ g_file_close(l_cfg->fd); /* if syslog is enabled, close it */ if (l_cfg->enable_syslog) { closelog(); } /* freeing allocated memory */ if (0 != l_cfg->log_file) { g_free(l_cfg->log_file); l_cfg->log_file = 0; } if (0 != l_cfg->program_name) { g_free(l_cfg->program_name); l_cfg->program_name = 0; } } /******************************************************************************/ int DEFAULT_CC log_text2level(char* buf) { if (0 == g_strcasecmp(buf, "0") || 0 == g_strcasecmp(buf, "core")) { return LOG_LEVEL_ALWAYS; } else if (0 == g_strcasecmp(buf, "1") || 0 == g_strcasecmp(buf, "error")) { return LOG_LEVEL_ERROR; } else if (0 == g_strcasecmp(buf, "2") || 0 == g_strcasecmp(buf, "warn") || 0 == g_strcasecmp(buf, "warning")) { return LOG_LEVEL_WARNING; } else if (0 == g_strcasecmp(buf, "3") || 0 == g_strcasecmp(buf, "info")) { return LOG_LEVEL_INFO; } return LOG_LEVEL_DEBUG; } xrdp-0.6.0/common/log.h000066400000000000000000000047701203155130500147170ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2005-2010 */ #ifndef LOG_H #define LOG_H #include #include "arch.h" /* logging buffer size */ #define LOG_BUFFER_SIZE 1024 /* logging levels */ #define LOG_LEVEL_ALWAYS 0 #define LOG_LEVEL_ERROR 1 #define LOG_LEVEL_WARNING 2 #define LOG_LEVEL_INFO 3 #define LOG_LEVEL_DEBUG 4 /* startup return values */ #define LOG_STARTUP_OK 0 #define LOG_ERROR_MALLOC 1 #define LOG_ERROR_NULL_FILE 2 #define LOG_ERROR_FILE_OPEN 3 #define LOG_ERROR_NO_CFG 4 #define LOG_ERROR_FILE_NOT_OPEN 5 /* enable threading */ /*#define LOG_ENABLE_THREAD*/ #ifdef DEBUG #define LOG_DBG(lcfg,args...) log_message((lcfg), LOG_LEVEL_DEBUG, args); #else #define LOG_DBG(lcfg,args...) #endif struct log_config { char* program_name; char* log_file; int fd; unsigned int log_level; int enable_syslog; unsigned int syslog_level; pthread_mutex_t log_lock; pthread_mutexattr_t log_lock_attr; }; /** * * @brief Logs a message. Optionally logs the same message on syslog * @param lvl The level of the logged message * @param msg The message to be logged * @return * */ int DEFAULT_CC log_message(struct log_config* l_cfg, const unsigned int lvl, const char* msg, ...); /** * * @brief Starts the logging subsystem * @param l_cfg loggging system configuration * @return * */ int DEFAULT_CC log_start(struct log_config* l_cfg); /** * * @brief Shuts down the logging subsystem * @param l_cfg pointer to the logging subsystem to stop * */ void DEFAULT_CC log_end(struct log_config* l_cfg); /** * * @brief Converts a string to a log level * @param s The string to convert * @return The corresponding level or LOG_LEVEL_DEBUG if error * */ int DEFAULT_CC log_text2level(char* s); #endif xrdp-0.6.0/common/os_calls.c000066400000000000000000001335601203155130500157300ustar00rootroot00000000000000/* Copyright (c) 2004-2012 Jay Sorg Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. generic operating system calls put all the os / arch define in here you want */ #if defined(HAVE_CONFIG_H) #include "config_ac.h" #endif #if defined(_WIN32) #include #include #else /* fix for solaris 10 with gcc 3.3.2 problem */ #if defined(sun) || defined(__sun) #define ctid_t id_t #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #endif #include #include #include #include #include #include "os_calls.h" #include "arch.h" /* for clearenv() */ #if defined(_WIN32) #else extern char** environ; #endif /* for solaris */ #if !defined(PF_LOCAL) #define PF_LOCAL AF_UNIX #endif #if !defined(INADDR_NONE) #define INADDR_NONE ((unsigned long)-1) #endif static char g_temp_base[128] = ""; static char g_temp_base_org[128] = ""; /*****************************************************************************/ int APP_CC g_rm_temp_dir(void) { if (g_temp_base[0] != 0) { if (!g_remove_dir(g_temp_base)) { printf("g_rm_temp_dir: removing temp directory [%s] failed\n", g_temp_base); } g_temp_base[0] = 0; } return 0; } /*****************************************************************************/ int APP_CC g_mk_temp_dir(const char* app_name) { if (app_name != 0) { if (app_name[0] != 0) { if (!g_directory_exist("/tmp/.xrdp")) { if (!g_create_dir("/tmp/.xrdp")) { printf("g_mk_temp_dir: g_create_dir failed\n"); return 1; } g_chmod_hex("/tmp/.xrdp", 0x1777); } snprintf(g_temp_base, sizeof(g_temp_base), "/tmp/.xrdp/%s-XXXXXX", app_name); snprintf(g_temp_base_org, sizeof(g_temp_base_org), "/tmp/.xrdp/%s-XXXXXX", app_name); if (mkdtemp(g_temp_base) == 0) { printf("g_mk_temp_dir: mkdtemp failed [%s]\n", g_temp_base); return 1; } } else { printf("g_mk_temp_dir: bad app name\n"); return 1; } } else { if (g_temp_base_org[0] == 0) { printf("g_mk_temp_dir: g_temp_base_org not set\n"); return 1; } g_strncpy(g_temp_base, g_temp_base_org, 127); if (mkdtemp(g_temp_base) == 0) { printf("g_mk_temp_dir: mkdtemp failed [%s]\n", g_temp_base); } } return 0; } /*****************************************************************************/ void APP_CC g_init(const char* app_name) { #if defined(_WIN32) WSADATA wsadata; WSAStartup(2, &wsadata); #endif setlocale(LC_CTYPE, ""); g_mk_temp_dir(app_name); } /*****************************************************************************/ void APP_CC g_deinit(void) { #if defined(_WIN32) WSACleanup(); #endif g_rm_temp_dir(); } /*****************************************************************************/ /* allocate memory, returns a pointer to it, size bytes are allocated, if zero is non zero, each byte will be set to zero */ void* APP_CC g_malloc(int size, int zero) { char* rv; rv = (char*)malloc(size); if (zero) { if (rv != 0) { memset(rv, 0, size); } } return rv; } /*****************************************************************************/ /* free the memory pointed to by ptr, ptr can be zero */ void APP_CC g_free(void* ptr) { if (ptr != 0) { free(ptr); } } /*****************************************************************************/ /* output text to stdout, try to use g_write / g_writeln instead to avoid linux / windows EOL problems */ void DEFAULT_CC g_printf(const char* format, ...) { va_list ap; va_start(ap, format); vfprintf(stdout, format, ap); va_end(ap); } /*****************************************************************************/ void DEFAULT_CC g_sprintf(char* dest, const char* format, ...) { va_list ap; va_start(ap, format); vsprintf(dest, format, ap); va_end(ap); } /*****************************************************************************/ void DEFAULT_CC g_snprintf(char* dest, int len, const char* format, ...) { va_list ap; va_start(ap, format); vsnprintf(dest, len, format, ap); va_end(ap); } /*****************************************************************************/ void DEFAULT_CC g_writeln(const char* format, ...) { va_list ap; va_start(ap, format); vfprintf(stdout, format, ap); va_end(ap); #if defined(_WIN32) g_printf("\r\n"); #else g_printf("\n"); #endif } /*****************************************************************************/ void DEFAULT_CC g_write(const char* format, ...) { va_list ap; va_start(ap, format); vfprintf(stdout, format, ap); va_end(ap); } /*****************************************************************************/ /* produce a hex dump */ void APP_CC g_hexdump(char* p, int len) { unsigned char* line; int i; int thisline; int offset; line = (unsigned char*)p; offset = 0; while (offset < len) { g_printf("%04x ", offset); thisline = len - offset; if (thisline > 16) { thisline = 16; } for (i = 0; i < thisline; i++) { g_printf("%02x ", line[i]); } for (; i < 16; i++) { g_printf(" "); } for (i = 0; i < thisline; i++) { g_printf("%c", (line[i] >= 0x20 && line[i] < 0x7f) ? line[i] : '.'); } g_writeln(""); offset += thisline; line += thisline; } } /*****************************************************************************/ void APP_CC g_memset(void* ptr, int val, int size) { memset(ptr, val, size); } /*****************************************************************************/ void APP_CC g_memcpy(void* d_ptr, const void* s_ptr, int size) { memcpy(d_ptr, s_ptr, size); } /*****************************************************************************/ int APP_CC g_getchar(void) { return getchar(); } /*****************************************************************************/ int APP_CC g_tcp_set_no_delay(int sck) { #if defined(_WIN32) int option_value; int option_len; #else int option_value; unsigned int option_len; #endif option_len = sizeof(option_value); /* SOL_TCP IPPROTO_TCP */ if (getsockopt(sck, IPPROTO_TCP, TCP_NODELAY, (char*)&option_value, &option_len) == 0) { if (option_value == 0) { option_value = 1; option_len = sizeof(option_value); setsockopt(sck, IPPROTO_TCP, TCP_NODELAY, (char*)&option_value, option_len); } } return 0; } /*****************************************************************************/ /* returns a newly created socket or -1 on error */ int APP_CC g_tcp_socket(void) { #if defined(_WIN32) int rv; int option_value; int option_len; #else int rv; int option_value; unsigned int option_len; #endif /* in win32 a socket is an unsigned int, in linux, its an int */ rv = (int)socket(PF_INET, SOCK_STREAM, 0); if (rv < 0) { return -1; } option_len = sizeof(option_value); if (getsockopt(rv, SOL_SOCKET, SO_REUSEADDR, (char*)&option_value, &option_len) == 0) { if (option_value == 0) { option_value = 1; option_len = sizeof(option_value); setsockopt(rv, SOL_SOCKET, SO_REUSEADDR, (char*)&option_value, option_len); } } option_len = sizeof(option_value); if (getsockopt(rv, SOL_SOCKET, SO_SNDBUF, (char*)&option_value, &option_len) == 0) { if (option_value < (1024 * 32)) { option_value = 1024 * 32; option_len = sizeof(option_value); setsockopt(rv, SOL_SOCKET, SO_SNDBUF, (char*)&option_value, option_len); } } return rv; } /*****************************************************************************/ int APP_CC g_tcp_local_socket(void) { #if defined(_WIN32) return 0; #else return socket(PF_LOCAL, SOCK_STREAM, 0); #endif } /*****************************************************************************/ void APP_CC g_tcp_close(int sck) { if (sck == 0) { return; } shutdown(sck, 2); #if defined(_WIN32) closesocket(sck); #else close(sck); #endif } /*****************************************************************************/ /* returns error, zero is good */ int APP_CC g_tcp_connect(int sck, const char* address, const char* port) { struct sockaddr_in s; struct hostent* h; g_memset(&s, 0, sizeof(struct sockaddr_in)); s.sin_family = AF_INET; s.sin_port = htons((tui16)atoi(port)); s.sin_addr.s_addr = inet_addr(address); if (s.sin_addr.s_addr == INADDR_NONE) { h = gethostbyname(address); if (h != 0) { if (h->h_name != 0) { if (h->h_addr_list != 0) { if ((*(h->h_addr_list)) != 0) { s.sin_addr.s_addr = *((int*)(*(h->h_addr_list))); } } } } } return connect(sck, (struct sockaddr*)&s, sizeof(struct sockaddr_in)); } /*****************************************************************************/ /* returns error, zero is good */ int APP_CC g_tcp_local_connect(int sck, const char* port) { #if defined(_WIN32) return -1; #else struct sockaddr_un s; memset(&s, 0, sizeof(struct sockaddr_un)); s.sun_family = AF_UNIX; strcpy(s.sun_path, port); return connect(sck, (struct sockaddr*)&s, sizeof(struct sockaddr_un)); #endif } /*****************************************************************************/ int APP_CC g_tcp_set_non_blocking(int sck) { unsigned long i; #if defined(_WIN32) i = 1; ioctlsocket(sck, FIONBIO, &i); #else i = fcntl(sck, F_GETFL); i = i | O_NONBLOCK; fcntl(sck, F_SETFL, i); #endif return 0; } /*****************************************************************************/ /* returns error, zero is good */ int APP_CC g_tcp_bind(int sck, char* port) { struct sockaddr_in s; memset(&s, 0, sizeof(struct sockaddr_in)); s.sin_family = AF_INET; s.sin_port = htons((tui16)atoi(port)); s.sin_addr.s_addr = INADDR_ANY; return bind(sck, (struct sockaddr*)&s, sizeof(struct sockaddr_in)); } /*****************************************************************************/ int APP_CC g_tcp_local_bind(int sck, char* port) { #if defined(_WIN32) return -1; #else struct sockaddr_un s; memset(&s, 0, sizeof(struct sockaddr_un)); s.sun_family = AF_UNIX; strcpy(s.sun_path, port); return bind(sck, (struct sockaddr*)&s, sizeof(struct sockaddr_un)); #endif } /*****************************************************************************/ /* returns error, zero is good */ int APP_CC g_tcp_bind_address(int sck, char* port, const char* address) { struct sockaddr_in s; memset(&s, 0, sizeof(struct sockaddr_in)); s.sin_family = AF_INET; s.sin_port = htons((tui16)atoi(port)); s.sin_addr.s_addr = INADDR_ANY; if (inet_aton(address, &s.sin_addr) < 0) { return -1; /* bad address */ } return bind(sck, (struct sockaddr*)&s, sizeof(struct sockaddr_in)); } /*****************************************************************************/ /* returns error, zero is good */ int APP_CC g_tcp_listen(int sck) { return listen(sck, 2); } /*****************************************************************************/ int APP_CC g_tcp_accept(int sck) { struct sockaddr_in s; #if defined(_WIN32) signed int i; #else unsigned int i; #endif i = sizeof(struct sockaddr_in); memset(&s, 0, i); return accept(sck, (struct sockaddr*)&s, &i); } /*****************************************************************************/ void APP_CC g_write_ip_address(int rcv_sck, char* ip_address) { struct sockaddr_in s; struct in_addr in; int len; int ip_port; memset(&s,0,sizeof(&s)); len = sizeof(s); getpeername(rcv_sck,(struct sockaddr*)&s, &len); memset(&in,0,sizeof(in)); in.s_addr = s.sin_addr.s_addr; ip_port = ntohs(s.sin_port); if (ip_port != 0) { sprintf(ip_address, "%s:%d - socket: %d", inet_ntoa(in), ip_port, rcv_sck); } else { sprintf(ip_address, "NULL:NULL - socket: %d", rcv_sck); } } /*****************************************************************************/ void APP_CC g_sleep(int msecs) { #if defined(_WIN32) Sleep(msecs); #else usleep(msecs * 1000); #endif } /*****************************************************************************/ int APP_CC g_tcp_last_error_would_block(int sck) { #if defined(_WIN32) return WSAGetLastError() == WSAEWOULDBLOCK; #else return (errno == EWOULDBLOCK) || (errno == EAGAIN) || (errno == EINPROGRESS); #endif } /*****************************************************************************/ int APP_CC g_tcp_recv(int sck, void* ptr, int len, int flags) { #if defined(_WIN32) return recv(sck, (char*)ptr, len, flags); #else return recv(sck, ptr, len, flags); #endif } /*****************************************************************************/ int APP_CC g_tcp_send(int sck, const void* ptr, int len, int flags) { #if defined(_WIN32) return send(sck, (const char*)ptr, len, flags); #else return send(sck, ptr, len, flags); #endif } /*****************************************************************************/ /* returns boolean */ int APP_CC g_tcp_socket_ok(int sck) { #if defined(_WIN32) int opt; int opt_len; #else int opt; unsigned int opt_len; #endif opt_len = sizeof(opt); if (getsockopt(sck, SOL_SOCKET, SO_ERROR, (char*)(&opt), &opt_len) == 0) { if (opt == 0) { return 1; } } return 0; } /*****************************************************************************/ /* wait 'millis' milliseconds for the socket to be able to write */ /* returns boolean */ int APP_CC g_tcp_can_send(int sck, int millis) { fd_set wfds; struct timeval time; int rv; time.tv_sec = millis / 1000; time.tv_usec = (millis * 1000) % 1000000; FD_ZERO(&wfds); if (sck > 0) { FD_SET(((unsigned int)sck), &wfds); rv = select(sck + 1, 0, &wfds, 0, &time); if (rv > 0) { return g_tcp_socket_ok(sck); } } return 0; } /*****************************************************************************/ /* wait 'millis' milliseconds for the socket to be able to receive */ /* returns boolean */ int APP_CC g_tcp_can_recv(int sck, int millis) { fd_set rfds; struct timeval time; int rv; time.tv_sec = millis / 1000; time.tv_usec = (millis * 1000) % 1000000; FD_ZERO(&rfds); if (sck > 0) { FD_SET(((unsigned int)sck), &rfds); rv = select(sck + 1, &rfds, 0, 0, &time); if (rv > 0) { return g_tcp_socket_ok(sck); } } return 0; } /*****************************************************************************/ int APP_CC g_tcp_select(int sck1, int sck2) { fd_set rfds; struct timeval time; int max = 0; int rv = 0; g_memset(&rfds,0,sizeof(fd_set)); g_memset(&time,0,sizeof(struct timeval)); time.tv_sec = 0; time.tv_usec = 0; FD_ZERO(&rfds); if (sck1 > 0) { FD_SET(((unsigned int)sck1), &rfds); } if (sck2 > 0) { FD_SET(((unsigned int)sck2), &rfds); } max = sck1; if (sck2 > max) { max = sck2; } rv = select(max + 1, &rfds, 0, 0, &time); if (rv > 0) { rv = 0; if (FD_ISSET(((unsigned int)sck1), &rfds)) { rv = rv | 1; } if (FD_ISSET(((unsigned int)sck2), &rfds)) { rv = rv | 2; } } else { rv = 0; } return rv; } /*****************************************************************************/ /* returns 0 on error */ tbus APP_CC g_create_wait_obj(char* name) { #ifdef _WIN32 tbus obj; obj = (tbus)CreateEvent(0, 1, 0, name); return obj; #else tbus obj; struct sockaddr_un sa; size_t len; tbus sck; int i; int safety; int unnamed; if (g_temp_base[0] == 0) { return 0; } sck = socket(PF_UNIX, SOCK_DGRAM, 0); if (sck < 0) { return 0; } safety = 0; g_memset(&sa, 0, sizeof(sa)); sa.sun_family = AF_UNIX; unnamed = 1; if (name != 0) { if (name[0] != 0) { unnamed = 0; } } if (unnamed) { do { if (safety > 100) { break; } safety++; g_random((char*)&i, sizeof(i)); len = sizeof(sa.sun_path); g_snprintf(sa.sun_path, len, "%s/auto_%8.8x", g_temp_base, i); len = sizeof(sa); } while (bind(sck, (struct sockaddr*)&sa, len) < 0); } else { do { if (safety > 100) { break; } safety++; g_random((char*)&i, sizeof(i)); len = sizeof(sa.sun_path); g_snprintf(sa.sun_path, len, "%s/%s_%8.8x", g_temp_base, name, i); len = sizeof(sa); } while (bind(sck, (struct sockaddr*)&sa, len) < 0); } obj = (tbus)sck; return obj; #endif } /*****************************************************************************/ /* returns 0 on error */ tbus APP_CC g_create_wait_obj_from_socket(tbus socket, int write) { #ifdef _WIN32 /* Create and return corresponding event handle for WaitForMultipleObjets */ WSAEVENT event; long lnetevent = 0; g_memset(&event,0,sizeof(WSAEVENT)); event = WSACreateEvent(); lnetevent = (write ? FD_WRITE : FD_READ) | FD_CLOSE; if (WSAEventSelect(socket, event, lnetevent) == 0) { return (tbus)event; } else { return 0; } #else return socket; #endif } /*****************************************************************************/ void APP_CC g_delete_wait_obj_from_socket(tbus wait_obj) { #ifdef _WIN32 if (wait_obj == 0) { return; } WSACloseEvent((HANDLE)wait_obj); #else #endif } /*****************************************************************************/ /* returns error */ int APP_CC g_set_wait_obj(tbus obj) { #ifdef _WIN32 if (obj == 0) { return 0; } SetEvent((HANDLE)obj); return 0; #else socklen_t sa_size; int s; struct sockaddr_un sa; if (obj == 0) { return 0; } if (g_tcp_can_recv((int)obj, 0)) { /* already signalled */ return 0; } sa_size = sizeof(sa); if (getsockname((int)obj, (struct sockaddr*)&sa, &sa_size) < 0) { return 1; } s = socket(PF_UNIX, SOCK_DGRAM, 0); if (s < 0) { return 1; } sendto(s, "sig", 4, 0, (struct sockaddr*)&sa, sa_size); close(s); return 0; #endif } /*****************************************************************************/ /* returns error */ int APP_CC g_reset_wait_obj(tbus obj) { #ifdef _WIN32 if (obj == 0) { return 0; } ResetEvent((HANDLE)obj); return 0; #else char buf[64]; if (obj == 0) { return 0; } while (g_tcp_can_recv((int)obj, 0)) { recvfrom((int)obj, &buf, 64, 0, 0, 0); } return 0; #endif } /*****************************************************************************/ /* returns boolean */ int APP_CC g_is_wait_obj_set(tbus obj) { #ifdef _WIN32 if (obj == 0) { return 0; } if (WaitForSingleObject((HANDLE)obj, 0) == WAIT_OBJECT_0) { return 1; } return 0; #else if (obj == 0) { return 0; } return g_tcp_can_recv((int)obj, 0); #endif } /*****************************************************************************/ /* returns error */ int APP_CC g_delete_wait_obj(tbus obj) { #ifdef _WIN32 if (obj == 0) { return 0; } /* Close event handle */ CloseHandle((HANDLE)obj); return 0; #else socklen_t sa_size; struct sockaddr_un sa; if (obj == 0) { return 0; } sa_size = sizeof(sa); if (getsockname((int)obj, (struct sockaddr*)&sa, &sa_size) < 0) { return 1; } close((int)obj); unlink(sa.sun_path); return 0; #endif } /*****************************************************************************/ /* returns error */ int APP_CC g_obj_wait(tbus* read_objs, int rcount, tbus* write_objs, int wcount, int mstimeout) { #ifdef _WIN32 HANDLE handles[256]; DWORD count; DWORD error; int j; int i; j = 0; count = rcount + wcount; for (i = 0; i < rcount; i++) { handles[j++] = (HANDLE)(read_objs[i]); } for (i = 0; i < wcount; i++) { handles[j++] = (HANDLE)(write_objs[i]); } if (mstimeout < 1) { mstimeout = INFINITE; } error = WaitForMultipleObjects(count, handles, FALSE, mstimeout); if (error == WAIT_FAILED) { return 1; } return 0; #else fd_set rfds; fd_set wfds; struct timeval time; struct timeval* ptime = (struct timeval *)NULL; int i = 0; int res = 0; int max = 0; int sck = 0; g_memset(&rfds,0,sizeof(fd_set)); g_memset(&wfds,0,sizeof(fd_set)); g_memset(&time,0,sizeof(struct timeval)); max = 0; if (mstimeout < 1) { ptime = (struct timeval *)NULL; } else { time.tv_sec = mstimeout / 1000; time.tv_usec = (mstimeout % 1000) * 1000; ptime = &time; } FD_ZERO(&rfds); FD_ZERO(&wfds); for (i = 0; i < rcount; i++) { sck = (int)(read_objs[i]); if (sck > 0) { FD_SET(sck, &rfds); if (sck > max) { max = sck; } } } for (i = 0; i < wcount; i++) { sck = (int)(write_objs[i]); if (sck > 0) { FD_SET(sck, &wfds); if (sck > max) { max = sck; } } } res = select(max + 1, &rfds, &wfds, 0, ptime); if (res < 0) { /* these are not really errors */ if ((errno == EAGAIN) || (errno == EWOULDBLOCK) || (errno == EINPROGRESS) || (errno == EINTR)) /* signal occurred */ { return 0; } return 1; } return 0; #endif } /*****************************************************************************/ void APP_CC g_random(char* data, int len) { #if defined(_WIN32) int index; srand(g_time1()); for (index = 0; index < len; index++) { data[index] = (char)rand(); /* rand returns a number between 0 and RAND_MAX */ } #else int fd; memset(data, 0x44, len); fd = open("/dev/urandom", O_RDONLY); if (fd == -1) { fd = open("/dev/random", O_RDONLY); } if (fd != -1) { if (read(fd, data, len) != len) { } close(fd); } #endif } /*****************************************************************************/ int APP_CC g_abs(int i) { return abs(i); } /*****************************************************************************/ int APP_CC g_memcmp(const void* s1, const void* s2, int len) { return memcmp(s1, s2, len); } /*****************************************************************************/ /* returns -1 on error, else return handle or file descriptor */ int APP_CC g_file_open(const char* file_name) { #if defined(_WIN32) return (int)CreateFileA(file_name, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); #else int rv; rv = open(file_name, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); if (rv == -1) { /* can't open read / write, try to open read only */ rv = open(file_name, O_RDONLY); } return rv; #endif } /*****************************************************************************/ /* returns error, always 0 */ int APP_CC g_file_close(int fd) { #if defined(_WIN32) CloseHandle((HANDLE)fd); #else close(fd); #endif return 0; } /*****************************************************************************/ /* read from file, returns the number of bytes read or -1 on error */ int APP_CC g_file_read(int fd, char* ptr, int len) { #if defined(_WIN32) if (ReadFile((HANDLE)fd, (LPVOID)ptr, (DWORD)len, (LPDWORD)&len, 0)) { return len; } else { return -1; } #else return read(fd, ptr, len); #endif } /*****************************************************************************/ /* write to file, returns the number of bytes writen or -1 on error */ int APP_CC g_file_write(int fd, char* ptr, int len) { #if defined(_WIN32) if (WriteFile((HANDLE)fd, (LPVOID)ptr, (DWORD)len, (LPDWORD)&len, 0)) { return len; } else { return -1; } #else return write(fd, ptr, len); #endif } /*****************************************************************************/ /* move file pointer, returns offset on success, -1 on failure */ int APP_CC g_file_seek(int fd, int offset) { #if defined(_WIN32) int rv; rv = (int)SetFilePointer((HANDLE)fd, offset, 0, FILE_BEGIN); if (rv == (int)INVALID_SET_FILE_POINTER) { return -1; } else { return rv; } #else return (int)lseek(fd, offset, SEEK_SET); #endif } /*****************************************************************************/ /* do a write lock on a file */ /* return boolean */ int APP_CC g_file_lock(int fd, int start, int len) { #if defined(_WIN32) return LockFile((HANDLE)fd, start, 0, len, 0); #else struct flock lock; lock.l_type = F_WRLCK; lock.l_whence = SEEK_SET; lock.l_start = start; lock.l_len = len; if (fcntl(fd, F_SETLK, &lock) == -1) { return 0; } return 1; #endif } /*****************************************************************************/ /* returns error */ int APP_CC g_chmod_hex(const char* filename, int flags) { #if defined(_WIN32) return 0; #else int fl; fl = 0; fl |= (flags & 0x4000) ? S_ISUID : 0; fl |= (flags & 0x2000) ? S_ISGID : 0; fl |= (flags & 0x1000) ? S_ISVTX : 0; fl |= (flags & 0x0400) ? S_IRUSR : 0; fl |= (flags & 0x0200) ? S_IWUSR : 0; fl |= (flags & 0x0100) ? S_IXUSR : 0; fl |= (flags & 0x0040) ? S_IRGRP : 0; fl |= (flags & 0x0020) ? S_IWGRP : 0; fl |= (flags & 0x0010) ? S_IXGRP : 0; fl |= (flags & 0x0004) ? S_IROTH : 0; fl |= (flags & 0x0002) ? S_IWOTH : 0; fl |= (flags & 0x0001) ? S_IXOTH : 0; return chmod(filename, fl); #endif } /*****************************************************************************/ /* returns error, zero is ok */ int APP_CC g_chown(const char* name, int uid, int gid) { return chown(name, uid, gid); } /*****************************************************************************/ /* returns error, always zero */ int APP_CC g_mkdir(const char* dirname) { #if defined(_WIN32) return 0; #else mkdir(dirname, S_IRWXU); return 0; #endif } /*****************************************************************************/ /* gets the current working directory and puts up to maxlen chars in dirname always returns 0 */ char* APP_CC g_get_current_dir(char* dirname, int maxlen) { #if defined(_WIN32) GetCurrentDirectoryA(maxlen, dirname); return 0; #else if (getcwd(dirname, maxlen) == 0) { } return 0; #endif } /*****************************************************************************/ /* returns error, zero on success and -1 on failure */ int APP_CC g_set_current_dir(char* dirname) { #if defined(_WIN32) if (SetCurrentDirectoryA(dirname)) { return 0; } else { return -1; } #else return chdir(dirname); #endif } /*****************************************************************************/ /* returns boolean, non zero if the file exists */ int APP_CC g_file_exist(const char* filename) { #if defined(_WIN32) return 0; // use FileAge(filename) <> -1 #else return access(filename, F_OK) == 0; #endif } /*****************************************************************************/ /* returns boolean, non zero if the directory exists */ int APP_CC g_directory_exist(const char* dirname) { #if defined(_WIN32) return 0; // use GetFileAttributes and check return value // is not -1 and FILE_ATTRIBUT_DIRECTORY bit is set #else struct stat st; if (stat(dirname, &st) == 0) { return S_ISDIR(st.st_mode); } else { return 0; } #endif } /*****************************************************************************/ /* returns boolean */ int APP_CC g_create_dir(const char* dirname) { #if defined(_WIN32) return CreateDirectoryA(dirname, 0); // test this #else return mkdir(dirname, (mode_t)-1) == 0; #endif } /*****************************************************************************/ /* returns boolean */ int APP_CC g_remove_dir(const char* dirname) { #if defined(_WIN32) return RemoveDirectoryA(dirname); // test this #else return rmdir(dirname) == 0; #endif } /*****************************************************************************/ /* returns non zero if the file was deleted */ int APP_CC g_file_delete(const char* filename) { #if defined(_WIN32) return DeleteFileA(filename); #else return unlink(filename) != -1; #endif } /*****************************************************************************/ /* returns file size, -1 on error */ int APP_CC g_file_get_size(const char* filename) { #if defined(_WIN32) return -1; #else struct stat st; if (stat(filename, &st) == 0) { return (int)(st.st_size); } else { return -1; } #endif } /*****************************************************************************/ /* returns length of text */ int APP_CC g_strlen(const char* text) { if (text == NULL) { return 0; } return strlen(text); } /*****************************************************************************/ /* returns dest */ char* APP_CC g_strcpy(char* dest, const char* src) { if (src == 0 && dest != 0) { dest[0] = 0; return dest; } if (dest == 0 || src == 0) { return 0; } return strcpy(dest, src); } /*****************************************************************************/ /* returns dest */ char* APP_CC g_strncpy(char* dest, const char* src, int len) { char* rv; if (src == 0 && dest != 0) { dest[0] = 0; return dest; } if (dest == 0 || src == 0) { return 0; } rv = strncpy(dest, src, len); dest[len] = 0; return rv; } /*****************************************************************************/ /* returns dest */ char* APP_CC g_strcat(char* dest, const char* src) { if (dest == 0 || src == 0) { return dest; } return strcat(dest, src); } /*****************************************************************************/ /* if in = 0, return 0 else return newly alloced copy of in */ char* APP_CC g_strdup(const char* in) { int len; char* p; if (in == 0) { return 0; } len = g_strlen(in); p = (char*)g_malloc(len + 1, 0); if (p != NULL) { g_strcpy(p, in); } return p; } /*****************************************************************************/ int APP_CC g_strcmp(const char* c1, const char* c2) { return strcmp(c1, c2); } /*****************************************************************************/ int APP_CC g_strncmp(const char* c1, const char* c2, int len) { return strncmp(c1, c2, len); } /*****************************************************************************/ int APP_CC g_strcasecmp(const char* c1, const char* c2) { #if defined(_WIN32) return stricmp(c1, c2); #else return strcasecmp(c1, c2); #endif } /*****************************************************************************/ int APP_CC g_strncasecmp(const char* c1, const char* c2, int len) { #if defined(_WIN32) return strnicmp(c1, c2, len); #else return strncasecmp(c1, c2, len); #endif } /*****************************************************************************/ int APP_CC g_atoi(const char* str) { if (str == 0) { return 0; } return atoi(str); } /*****************************************************************************/ int APP_CC g_htoi(char* str) { int len; int index; int rv; int val; int shift; rv = 0; len = strlen(str); index = len - 1; shift = 0; while (index >= 0) { val = 0; switch (str[index]) { case '1': val = 1; break; case '2': val = 2; break; case '3': val = 3; break; case '4': val = 4; break; case '5': val = 5; break; case '6': val = 6; break; case '7': val = 7; break; case '8': val = 8; break; case '9': val = 9; break; case 'a': case 'A': val = 10; break; case 'b': case 'B': val = 11; break; case 'c': case 'C': val = 12; break; case 'd': case 'D': val = 13; break; case 'e': case 'E': val = 14; break; case 'f': case 'F': val = 15; break; } rv = rv | (val << shift); index--; shift += 4; } return rv; } /*****************************************************************************/ int APP_CC g_pos(char* str, const char* to_find) { char* pp; pp = strstr(str, to_find); if (pp == 0) { return -1; } return (pp - str); } /*****************************************************************************/ int APP_CC g_mbstowcs(twchar* dest, const char* src, int n) { wchar_t* ldest; int rv; ldest = (wchar_t*)dest; rv = mbstowcs(ldest, src, n); return rv; } /*****************************************************************************/ int APP_CC g_wcstombs(char* dest, const twchar* src, int n) { const wchar_t* lsrc; int rv; lsrc = (const wchar_t*)src; rv = wcstombs(dest, lsrc, n); return rv; } /*****************************************************************************/ /* returns error */ /* trim spaces and tabs, anything <= space */ /* trim_flags 1 trim left, 2 trim right, 3 trim both, 4 trim through */ /* this will always shorten the string or not change it */ int APP_CC g_strtrim(char* str, int trim_flags) { int index; int len; int text1_index; int got_char; wchar_t* text; wchar_t* text1; len = mbstowcs(0, str, 0); if (len < 1) { return 0; } if ((trim_flags < 1) || (trim_flags > 4)) { return 1; } text = (wchar_t*)malloc(len * sizeof(wchar_t) + 8); text1 = (wchar_t*)malloc(len * sizeof(wchar_t) + 8); text1_index = 0; mbstowcs(text, str, len + 1); switch (trim_flags) { case 4: /* trim through */ for (index = 0; index < len; index++) { if (text[index] > 32) { text1[text1_index] = text[index]; text1_index++; } } text1[text1_index] = 0; break; case 3: /* trim both */ got_char = 0; for (index = 0; index < len; index++) { if (got_char) { text1[text1_index] = text[index]; text1_index++; } else { if (text[index] > 32) { text1[text1_index] = text[index]; text1_index++; got_char = 1; } } } text1[text1_index] = 0; len = text1_index; /* trim right */ for (index = len - 1; index >= 0; index--) { if (text1[index] > 32) { break; } } text1_index = index + 1; text1[text1_index] = 0; break; case 2: /* trim right */ /* copy it */ for (index = 0; index < len; index++) { text1[text1_index] = text[index]; text1_index++; } /* trim right */ for (index = len - 1; index >= 0; index--) { if (text1[index] > 32) { break; } } text1_index = index + 1; text1[text1_index] = 0; break; case 1: /* trim left */ got_char = 0; for (index = 0; index < len; index++) { if (got_char) { text1[text1_index] = text[index]; text1_index++; } else { if (text[index] > 32) { text1[text1_index] = text[index]; text1_index++; got_char = 1; } } } text1[text1_index] = 0; break; } wcstombs(str, text1, text1_index + 1); free(text); free(text1); return 0; } /*****************************************************************************/ long APP_CC g_load_library(char* in) { #if defined(_WIN32) return (long)LoadLibraryA(in); #else return (long)dlopen(in, RTLD_LOCAL | RTLD_LAZY); #endif } /*****************************************************************************/ int APP_CC g_free_library(long lib) { if (lib == 0) { return 0; } #if defined(_WIN32) return FreeLibrary((HMODULE)lib); #else return dlclose((void*)lib); #endif } /*****************************************************************************/ /* returns NULL if not found */ void* APP_CC g_get_proc_address(long lib, const char* name) { if (lib == 0) { return 0; } #if defined(_WIN32) return GetProcAddress((HMODULE)lib, name); #else return dlsym((void*)lib, name); #endif } /*****************************************************************************/ /* does not work in win32 */ int APP_CC g_system(char* aexec) { #if defined(_WIN32) return 0; #else return system(aexec); #endif } /*****************************************************************************/ /* does not work in win32 */ char* APP_CC g_get_strerror(void) { #if defined(_WIN32) return 0; #else return strerror(errno); #endif } /*****************************************************************************/ int APP_CC g_get_errno(void) { #if defined(_WIN32) return GetLastError(); #else return errno; #endif } /*****************************************************************************/ /* does not work in win32 */ int APP_CC g_execvp(const char* p1, char* args[]) { #if defined(_WIN32) return 0; #else int rv; g_rm_temp_dir(); rv = execvp(p1, args); g_mk_temp_dir(0); return rv; #endif } /*****************************************************************************/ /* does not work in win32 */ int APP_CC g_execlp3(const char* a1, const char* a2, const char* a3) { #if defined(_WIN32) return 0; #else int rv; g_rm_temp_dir(); rv = execlp(a1, a2, a3, (void*)0); g_mk_temp_dir(0); return rv; #endif } /*****************************************************************************/ /* does not work in win32 */ void APP_CC g_signal_child_stop(void (*func)(int)) { #if defined(_WIN32) #else signal(SIGCHLD, func); #endif } /*****************************************************************************/ /* does not work in win32 */ void APP_CC g_signal_hang_up(void (*func)(int)) { #if defined(_WIN32) #else signal(SIGHUP, func); #endif } /*****************************************************************************/ /* does not work in win32 */ void APP_CC g_signal_user_interrupt(void (*func)(int)) { #if defined(_WIN32) #else signal(SIGINT, func); #endif } /*****************************************************************************/ /* does not work in win32 */ void APP_CC g_signal_kill(void (*func)(int)) { #if defined(_WIN32) #else signal(SIGKILL, func); #endif } /*****************************************************************************/ /* does not work in win32 */ void APP_CC g_signal_terminate(void (*func)(int)) { #if defined(_WIN32) #else signal(SIGTERM, func); #endif } /*****************************************************************************/ /* does not work in win32 */ void APP_CC g_signal_pipe(void (*func)(int)) { #if defined(_WIN32) #else signal(SIGPIPE, func); #endif } /*****************************************************************************/ /* does not work in win32 */ void APP_CC g_signal_usr1(void (*func)(int)) { #if defined(_WIN32) #else signal(SIGUSR1, func); #endif } /*****************************************************************************/ /* does not work in win32 */ int APP_CC g_fork(void) { #if defined(_WIN32) return 0; #else int rv; rv = fork(); if (rv == 0) /* child */ { g_mk_temp_dir(0); } return rv; #endif } /*****************************************************************************/ /* does not work in win32 */ int APP_CC g_setgid(int pid) { #if defined(_WIN32) return 0; #else return setgid(pid); #endif } /*****************************************************************************/ /* returns error, zero is success, non zero is error */ /* does not work in win32 */ int APP_CC g_initgroups(const char* user, int gid) { #if defined(_WIN32) return 0; #else return initgroups(user, gid); #endif } /*****************************************************************************/ /* does not work in win32 */ /* returns user id */ int APP_CC g_getuid(void) { #if defined(_WIN32) return 0; #else return getuid(); #endif } /*****************************************************************************/ /* does not work in win32 */ /* On success, zero is returned. On error, -1 is returned */ int APP_CC g_setuid(int pid) { #if defined(_WIN32) return 0; #else return setuid(pid); #endif } /*****************************************************************************/ /* does not work in win32 returns pid of process that exits or zero if signal occurred */ int APP_CC g_waitchild(void) { #if defined(_WIN32) return 0; #else int wstat; int rv; rv = waitpid(0, &wstat, WNOHANG); if (rv == -1) { if (errno == EINTR) /* signal occurred */ { rv = 0; } } return rv; #endif } /*****************************************************************************/ /* does not work in win32 returns pid of process that exits or zero if signal occurred */ int APP_CC g_waitpid(int pid) { #if defined(_WIN32) return 0; #else int rv = 0; if (pid < 0) { rv = -1; } else { rv = waitpid(pid, 0, 0); if (rv == -1) { if (errno == EINTR) /* signal occurred */ { rv = 0; } } } return rv; #endif } /*****************************************************************************/ /* does not work in win32 */ void APP_CC g_clearenv(void) { #if defined(_WIN32) #else environ = 0; #endif } /*****************************************************************************/ /* does not work in win32 */ int APP_CC g_setenv(const char* name, const char* value, int rewrite) { #if defined(_WIN32) return 0; #else return setenv(name, value, rewrite); #endif } /*****************************************************************************/ /* does not work in win32 */ char* APP_CC g_getenv(const char* name) { #if defined(_WIN32) return 0; #else return getenv(name); #endif } /*****************************************************************************/ int APP_CC g_exit(int exit_code) { _exit(exit_code); return 0; } /*****************************************************************************/ int APP_CC g_getpid(void) { #if defined(_WIN32) return (int)GetCurrentProcessId(); #else return (int)getpid(); #endif } /*****************************************************************************/ /* does not work in win32 */ int APP_CC g_sigterm(int pid) { #if defined(_WIN32) return 0; #else return kill(pid, SIGTERM); #endif } /*****************************************************************************/ /* returns 0 if ok */ /* does not work in win32 */ int APP_CC g_getuser_info(const char* username, int* gid, int* uid, char* shell, char* dir, char* gecos) { #if defined(_WIN32) return 1; #else struct passwd* pwd_1; pwd_1 = getpwnam(username); if (pwd_1 != 0) { if (gid != 0) { *gid = pwd_1->pw_gid; } if (uid != 0) { *uid = pwd_1->pw_uid; } if (dir != 0) { g_strcpy(dir, pwd_1->pw_dir); } if (shell != 0) { g_strcpy(shell, pwd_1->pw_shell); } if (gecos != 0) { g_strcpy(gecos, pwd_1->pw_gecos); } return 0; } return 1; #endif } /*****************************************************************************/ /* returns 0 if ok */ /* does not work in win32 */ int APP_CC g_getgroup_info(const char* groupname, int* gid) { #if defined(_WIN32) return 1; #else struct group* g; g = getgrnam(groupname); if (g != 0) { if (gid != 0) { *gid = g->gr_gid; } return 0; } return 1; #endif } /*****************************************************************************/ /* returns error */ /* if zero is returned, then ok is set */ /* does not work in win32 */ int APP_CC g_check_user_in_group(const char* username, int gid, int* ok) { #if defined(_WIN32) return 1; #else struct group* groups; int i; groups = getgrgid(gid); if (groups == 0) { return 1; } *ok = 0; i = 0; while (0 != groups->gr_mem[i]) { if (0 == g_strcmp(groups->gr_mem[i], username)) { *ok = 1; break; } i++; } return 0; #endif } /*****************************************************************************/ /* returns the time since the Epoch (00:00:00 UTC, January 1, 1970), measured in seconds. for windows, returns the number of seconds since the machine was started. */ int APP_CC g_time1(void) { #if defined(_WIN32) return GetTickCount() / 1000; #else return time(0); #endif } /*****************************************************************************/ /* returns the number of milliseconds since the machine was started. */ int APP_CC g_time2(void) { #if defined(_WIN32) return (int)GetTickCount(); #else struct tms tm; clock_t num_ticks = 0; g_memset(&tm,0,sizeof(struct tms)); num_ticks = times(&tm); return (int)(num_ticks * 10); #endif } /*****************************************************************************/ /* returns time in milliseconds, uses gettimeofday does not work in win32 */ int APP_CC g_time3(void) { #if defined(_WIN32) return 0; #else struct timeval tp; gettimeofday(&tp, 0); return (tp.tv_sec * 1000) + (tp.tv_usec / 1000); #endif } xrdp-0.6.0/common/os_calls.h000066400000000000000000000151211203155130500157250ustar00rootroot00000000000000/* Copyright (c) 2004-2012 Jay Sorg Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. generic operating system calls */ #if !defined(OS_CALLS_H) #define OS_CALLS_H #ifndef NULL #define NULL 0 #endif #include "arch.h" int APP_CC g_rm_temp_dir(void); int APP_CC g_mk_temp_dir(const char* app_name); void APP_CC g_init(const char* app_name); void APP_CC g_deinit(void); void* APP_CC g_malloc(int size, int zero); void APP_CC g_free(void* ptr); void DEFAULT_CC g_printf(const char *format, ...); void DEFAULT_CC g_sprintf(char* dest, const char* format, ...); void DEFAULT_CC g_snprintf(char* dest, int len, const char* format, ...); void DEFAULT_CC g_writeln(const char* format, ...); void DEFAULT_CC g_write(const char* format, ...); void APP_CC g_hexdump(char* p, int len); void APP_CC g_memset(void* ptr, int val, int size); void APP_CC g_memcpy(void* d_ptr, const void* s_ptr, int size); int APP_CC g_getchar(void); int APP_CC g_tcp_set_no_delay(int sck); int APP_CC g_tcp_socket(void); int APP_CC g_tcp_local_socket(void); void APP_CC g_tcp_close(int sck); int APP_CC g_tcp_connect(int sck, const char* address, const char* port); int APP_CC g_tcp_local_connect(int sck, const char* port); int APP_CC g_tcp_force_send(int sck, char* data, int len); int APP_CC g_tcp_force_recv(int sck, char* data, int len); int APP_CC g_tcp_set_non_blocking(int sck); int APP_CC g_tcp_bind(int sck, char* port); int APP_CC g_tcp_local_bind(int sck, char* port); int APP_CC g_tcp_bind_address(int sck, char* port, const char* address); int APP_CC g_tcp_listen(int sck); int APP_CC g_tcp_accept(int sck); int APP_CC g_tcp_recv(int sck, void* ptr, int len, int flags); int APP_CC g_tcp_send(int sck, const void* ptr, int len, int flags); int APP_CC g_tcp_last_error_would_block(int sck); int APP_CC g_tcp_socket_ok(int sck); int APP_CC g_tcp_can_send(int sck, int millis); int APP_CC g_tcp_can_recv(int sck, int millis); int APP_CC g_tcp_select(int sck1, int sck2); void APP_CC g_write_ip_address(int rcv_sck, char* ip_address); void APP_CC g_sleep(int msecs); tbus APP_CC g_create_wait_obj(char* name); tbus APP_CC g_create_wait_obj_from_socket(tbus socket, int write); void APP_CC g_delete_wait_obj_from_socket(tbus wait_obj); int APP_CC g_set_wait_obj(tbus obj); int APP_CC g_reset_wait_obj(tbus obj); int APP_CC g_is_wait_obj_set(tbus obj); int APP_CC g_delete_wait_obj(tbus obj); int APP_CC g_obj_wait(tbus* read_objs, int rcount, tbus* write_objs, int wcount, int mstimeout); void APP_CC g_random(char* data, int len); int APP_CC g_abs(int i); int APP_CC g_memcmp(const void* s1, const void* s2, int len); int APP_CC g_file_open(const char* file_name); int APP_CC g_file_close(int fd); int APP_CC g_file_read(int fd, char* ptr, int len); int APP_CC g_file_write(int fd, char* ptr, int len); int APP_CC g_file_seek(int fd, int offset); int APP_CC g_file_lock(int fd, int start, int len); int APP_CC g_chmod_hex(const char* filename, int flags); int APP_CC g_chown(const char* name, int uid, int gid); int APP_CC g_mkdir(const char* dirname); char* APP_CC g_get_current_dir(char* dirname, int maxlen); int APP_CC g_set_current_dir(char* dirname); int APP_CC g_file_exist(const char* filename); int APP_CC g_directory_exist(const char* dirname); int APP_CC g_create_dir(const char* dirname); int APP_CC g_remove_dir(const char* dirname); int APP_CC g_file_delete(const char* filename); int APP_CC g_file_get_size(const char* filename); int APP_CC g_strlen(const char* text); char* APP_CC g_strcpy(char* dest, const char* src); char* APP_CC g_strncpy(char* dest, const char* src, int len); char* APP_CC g_strcat(char* dest, const char* src); char* APP_CC g_strdup(const char* in); int APP_CC g_strcmp(const char* c1, const char* c2); int APP_CC g_strncmp(const char* c1, const char* c2, int len); int APP_CC g_strcasecmp(const char* c1, const char* c2); int APP_CC g_strncasecmp(const char* c1, const char* c2, int len); int APP_CC g_atoi(const char* str); int APP_CC g_htoi(char* str); int APP_CC g_pos(char* str, const char* to_find); int APP_CC g_mbstowcs(twchar* dest, const char* src, int n); int APP_CC g_wcstombs(char* dest, const twchar* src, int n); int APP_CC g_strtrim(char* str, int trim_flags); long APP_CC g_load_library(char* in); int APP_CC g_free_library(long lib); void* APP_CC g_get_proc_address(long lib, const char* name); int APP_CC g_system(char* aexec); char* APP_CC g_get_strerror(void); int APP_CC g_get_errno(void); int APP_CC g_execvp(const char* p1, char* args[]); int APP_CC g_execlp3(const char* a1, const char* a2, const char* a3); void APP_CC g_signal_child_stop(void (*func)(int)); void APP_CC g_signal_hang_up(void (*func)(int)); void APP_CC g_signal_user_interrupt(void (*func)(int)); void APP_CC g_signal_kill(void (*func)(int)); void APP_CC g_signal_terminate(void (*func)(int)); void APP_CC g_signal_pipe(void (*func)(int)); void APP_CC g_signal_usr1(void (*func)(int)); int APP_CC g_fork(void); int APP_CC g_setgid(int pid); int APP_CC g_initgroups(const char* user, int gid); int APP_CC g_getuid(void); int APP_CC g_setuid(int pid); int APP_CC g_waitchild(void); int APP_CC g_waitpid(int pid); void APP_CC g_clearenv(void); int APP_CC g_setenv(const char* name, const char* value, int rewrite); char* APP_CC g_getenv(const char* name); int APP_CC g_exit(int exit_code); int APP_CC g_getpid(void); int APP_CC g_sigterm(int pid); int APP_CC g_getuser_info(const char* username, int* gid, int* uid, char* shell, char* dir, char* gecos); int APP_CC g_getgroup_info(const char* groupname, int* gid); int APP_CC g_check_user_in_group(const char* username, int gid, int* ok); int APP_CC g_time1(void); int APP_CC g_time2(void); int APP_CC g_time3(void); #endif xrdp-0.6.0/common/parse.h000066400000000000000000000201601203155130500152370ustar00rootroot00000000000000/* Copyright (c) 2004-2010 Jay Sorg Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Parsing structs and macros based on parse.h from rdesktop this is a super fast stream method, you bet needed functions g_malloc, g_free, g_memset, g_memcpy */ #if !defined(PARSE_H) #define PARSE_H #include "arch.h" #if defined(L_ENDIAN) #elif defined(B_ENDIAN) #else #error Unknown endianness. #endif /* parser state */ struct stream { char* p; char* end; char* data; int size; /* offsets of various headers */ char* iso_hdr; char* mcs_hdr; char* sec_hdr; char* rdp_hdr; char* channel_hdr; char* next_packet; }; /******************************************************************************/ #define s_check(s) ((s)->p <= (s)->end) /******************************************************************************/ #define s_check_rem(s, n) ((s)->p + (n) <= (s)->end) /******************************************************************************/ #define s_check_end(s) ((s)->p == (s)->end) /******************************************************************************/ #define make_stream(s) \ (s) = (struct stream*)g_malloc(sizeof(struct stream), 1) /******************************************************************************/ #define init_stream(s, v) do \ { \ if ((v) > (s)->size) \ { \ g_free((s)->data); \ (s)->data = (char*)g_malloc((v), 0); \ (s)->size = (v); \ } \ (s)->p = (s)->data; \ (s)->end = (s)->data; \ (s)->next_packet = 0; \ } while (0) /******************************************************************************/ #define free_stream(s) do \ { \ if ((s) != 0) \ { \ g_free((s)->data); \ } \ g_free((s)); \ } while (0) /******************************************************************************/ #define s_push_layer(s, h, n) do \ { \ (s)->h = (s)->p; \ (s)->p += (n); \ } while (0) /******************************************************************************/ #define s_pop_layer(s, h) \ (s)->p = (s)->h /******************************************************************************/ #define s_mark_end(s) \ (s)->end = (s)->p /******************************************************************************/ #define in_sint8(s, v) do \ { \ (v) = *((signed char*)((s)->p)); \ (s)->p++; \ } while (0) /******************************************************************************/ #define in_uint8(s, v) do \ { \ (v) = *((unsigned char*)((s)->p)); \ (s)->p++; \ } while (0) /******************************************************************************/ #if defined(B_ENDIAN) || defined(NEED_ALIGN) #define in_sint16_le(s, v) do \ { \ (v) = (signed short) \ ( \ (*((unsigned char*)((s)->p + 0)) << 0) | \ (*((unsigned char*)((s)->p + 1)) << 8) \ ); \ (s)->p += 2; \ } while (0) #else #define in_sint16_le(s, v) do \ { \ (v) = *((signed short*)((s)->p)); \ (s)->p += 2; \ } while (0) #endif /******************************************************************************/ #if defined(B_ENDIAN) || defined(NEED_ALIGN) #define in_uint16_le(s, v) do \ { \ (v) = (unsigned short) \ ( \ (*((unsigned char*)((s)->p + 0)) << 0) | \ (*((unsigned char*)((s)->p + 1)) << 8) \ ); \ (s)->p += 2; \ } while (0) #else #define in_uint16_le(s, v) do \ { \ (v) = *((unsigned short*)((s)->p)); \ (s)->p += 2; \ } while (0) #endif /******************************************************************************/ #define in_uint16_be(s, v) do \ { \ (v) = *((unsigned char*)((s)->p)); \ (s)->p++; \ (v) <<= 8; \ (v) |= *((unsigned char*)((s)->p)); \ (s)->p++; \ } while (0) /******************************************************************************/ #if defined(B_ENDIAN) || defined(NEED_ALIGN) #define in_uint32_le(s, v) do \ { \ (v) = (unsigned int) \ ( \ (*((unsigned char*)((s)->p + 0)) << 0) | \ (*((unsigned char*)((s)->p + 1)) << 8) | \ (*((unsigned char*)((s)->p + 2)) << 16) | \ (*((unsigned char*)((s)->p + 3)) << 24) \ ); \ (s)->p += 4; \ } while (0) #else #define in_uint32_le(s, v) do \ { \ (v) = *((unsigned int*)((s)->p)); \ (s)->p += 4; \ } while (0) #endif /******************************************************************************/ #define in_uint32_be(s, v) do \ { \ (v) = *((unsigned char*)((s)->p)); \ (s)->p++; \ (v) <<= 8; \ (v) |= *((unsigned char*)((s)->p)); \ (s)->p++; \ (v) <<= 8; \ (v) |= *((unsigned char*)((s)->p)); \ (s)->p++; \ (v) <<= 8; \ (v) |= *((unsigned char*)((s)->p)); \ (s)->p++; \ } while (0) /******************************************************************************/ #define out_uint8(s, v) do \ { \ *((s)->p) = (unsigned char)(v); \ (s)->p++; \ } while (0) /******************************************************************************/ #if defined(B_ENDIAN) || defined(NEED_ALIGN) #define out_uint16_le(s, v) do \ { \ *((s)->p) = (unsigned char)((v) >> 0); \ (s)->p++; \ *((s)->p) = (unsigned char)((v) >> 8); \ (s)->p++; \ } while (0) #else #define out_uint16_le(s, v) do \ { \ *((unsigned short*)((s)->p)) = (unsigned short)(v); \ (s)->p += 2; \ } while (0) #endif /******************************************************************************/ #define out_uint16_be(s, v) do \ { \ *((s)->p) = (unsigned char)((v) >> 8); \ (s)->p++; \ *((s)->p) = (unsigned char)((v) >> 0); \ (s)->p++; \ } while (0) /******************************************************************************/ #if defined(B_ENDIAN) || defined(NEED_ALIGN) #define out_uint32_le(s, v) do \ { \ *((s)->p) = (unsigned char)((v) >> 0); \ (s)->p++; \ *((s)->p) = (unsigned char)((v) >> 8); \ (s)->p++; \ *((s)->p) = (unsigned char)((v) >> 16); \ (s)->p++; \ *((s)->p) = (unsigned char)((v) >> 24); \ (s)->p++; \ } while (0) #else #define out_uint32_le(s, v) do \ { \ *((unsigned int*)((s)->p)) = (v); \ (s)->p += 4; \ } while (0) #endif /******************************************************************************/ #define out_uint32_be(s, v) do \ { \ *((s)->p) = (unsigned char)((v) >> 24); \ s->p++; \ *((s)->p) = (unsigned char)((v) >> 16); \ s->p++; \ *((s)->p) = (unsigned char)((v) >> 8); \ s->p++; \ *((s)->p) = (unsigned char)(v); \ (s)->p++; \ } while (0) /******************************************************************************/ #define in_uint8p(s, v, n) do \ { \ (v) = (s)->p; \ (s)->p += (n); \ } while (0) /******************************************************************************/ #define in_uint8a(s, v, n) do \ { \ g_memcpy((v), (s)->p, (n)); \ (s)->p += (n); \ } while (0) /******************************************************************************/ #define in_uint8s(s, n) \ (s)->p += (n) /******************************************************************************/ #define out_uint8p(s, v, n) do \ { \ g_memcpy((s)->p, (v), (n)); \ (s)->p += (n); \ } while (0) /******************************************************************************/ #define out_uint8a(s, v, n) \ out_uint8p((s), (v), (n)) /******************************************************************************/ #define out_uint8s(s, n) do \ { \ g_memset((s)->p, 0, (n)); \ (s)->p += (n); \ } while (0) #endif xrdp-0.6.0/common/ssl_calls.c000066400000000000000000000203341203155130500161020ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2004-2010 ssl calls */ #include /* needed for openssl headers */ #include #include #include #include #include #include #include #include "os_calls.h" #include "arch.h" #include "ssl_calls.h" #if defined(OPENSSL_VERSION_NUMBER) && (OPENSSL_VERSION_NUMBER >= 0x0090800f) #undef OLD_RSA_GEN1 #else #define OLD_RSA_GEN1 #endif /*****************************************************************************/ int ssl_init(void) { SSL_load_error_strings(); SSL_library_init(); return 0; } /*****************************************************************************/ int ssl_finish(void) { return 0; } /* rc4 stuff */ /*****************************************************************************/ void* APP_CC ssl_rc4_info_create(void) { return g_malloc(sizeof(RC4_KEY), 1); } /*****************************************************************************/ void APP_CC ssl_rc4_info_delete(void* rc4_info) { g_free(rc4_info); } /*****************************************************************************/ void APP_CC ssl_rc4_set_key(void* rc4_info, char* key, int len) { RC4_set_key((RC4_KEY*)rc4_info, len, (tui8*)key); } /*****************************************************************************/ void APP_CC ssl_rc4_crypt(void* rc4_info, char* data, int len) { RC4((RC4_KEY*)rc4_info, len, (tui8*)data, (tui8*)data); } /* sha1 stuff */ /*****************************************************************************/ void* APP_CC ssl_sha1_info_create(void) { return g_malloc(sizeof(SHA_CTX), 1); } /*****************************************************************************/ void APP_CC ssl_sha1_info_delete(void* sha1_info) { g_free(sha1_info); } /*****************************************************************************/ void APP_CC ssl_sha1_clear(void* sha1_info) { SHA1_Init((SHA_CTX*)sha1_info); } /*****************************************************************************/ void APP_CC ssl_sha1_transform(void* sha1_info, char* data, int len) { SHA1_Update((SHA_CTX*)sha1_info, data, len); } /*****************************************************************************/ void APP_CC ssl_sha1_complete(void* sha1_info, char* data) { SHA1_Final((tui8*)data, (SHA_CTX*)sha1_info); } /* md5 stuff */ /*****************************************************************************/ void* APP_CC ssl_md5_info_create(void) { return g_malloc(sizeof(MD5_CTX), 1); } /*****************************************************************************/ void APP_CC ssl_md5_info_delete(void* md5_info) { g_free(md5_info); } /*****************************************************************************/ void APP_CC ssl_md5_clear(void* md5_info) { MD5_Init((MD5_CTX*)md5_info); } /*****************************************************************************/ void APP_CC ssl_md5_transform(void* md5_info, char* data, int len) { MD5_Update((MD5_CTX*)md5_info, data, len); } /*****************************************************************************/ void APP_CC ssl_md5_complete(void* md5_info, char* data) { MD5_Final((tui8*)data, (MD5_CTX*)md5_info); } /*****************************************************************************/ static void APP_CC ssl_reverse_it(char* p, int len) { int i; int j; char temp; i = 0; j = len - 1; while (i < j) { temp = p[i]; p[i] = p[j]; p[j] = temp; i++; j--; } } /*****************************************************************************/ int APP_CC ssl_mod_exp(char* out, int out_len, char* in, int in_len, char* mod, int mod_len, char* exp, int exp_len) { BN_CTX* ctx; BIGNUM lmod; BIGNUM lexp; BIGNUM lin; BIGNUM lout; int rv; char* l_out; char* l_in; char* l_mod; char* l_exp; l_out = (char*)g_malloc(out_len, 1); l_in = (char*)g_malloc(in_len, 1); l_mod = (char*)g_malloc(mod_len, 1); l_exp = (char*)g_malloc(exp_len, 1); g_memcpy(l_in, in, in_len); g_memcpy(l_mod, mod, mod_len); g_memcpy(l_exp, exp, exp_len); ssl_reverse_it(l_in, in_len); ssl_reverse_it(l_mod, mod_len); ssl_reverse_it(l_exp, exp_len); ctx = BN_CTX_new(); BN_init(&lmod); BN_init(&lexp); BN_init(&lin); BN_init(&lout); BN_bin2bn((tui8*)l_mod, mod_len, &lmod); BN_bin2bn((tui8*)l_exp, exp_len, &lexp); BN_bin2bn((tui8*)l_in, in_len, &lin); BN_mod_exp(&lout, &lin, &lexp, &lmod, ctx); rv = BN_bn2bin(&lout, (tui8*)l_out); if (rv <= out_len) { ssl_reverse_it(l_out, rv); g_memcpy(out, l_out, out_len); } else { rv = 0; } BN_free(&lin); BN_free(&lout); BN_free(&lexp); BN_free(&lmod); BN_CTX_free(ctx); g_free(l_out); g_free(l_in); g_free(l_mod); g_free(l_exp); return rv; } #if defined(OLD_RSA_GEN1) /*****************************************************************************/ /* returns error generates a new rsa key exp is passed in and mod and pri are passed out */ int APP_CC ssl_gen_key_xrdp1(int key_size_in_bits, char* exp, int exp_len, char* mod, int mod_len, char* pri, int pri_len) { int my_e; RSA* my_key; char* lmod; char* lpri; tui8* lexp; int error; int len; if ((exp_len != 4) || (mod_len != 64) || (pri_len != 64)) { return 1; } lmod = (char*)g_malloc(mod_len, 0); lpri = (char*)g_malloc(pri_len, 0); lexp = (tui8*)exp; my_e = lexp[0]; my_e |= lexp[1] << 8; my_e |= lexp[2] << 16; my_e |= lexp[3] << 24; /* srand is in stdlib.h */ srand(g_time1()); my_key = RSA_generate_key(key_size_in_bits, my_e, 0, 0); error = my_key == 0; if (error == 0) { len = BN_num_bytes(my_key->n); error = len != mod_len; } if (error == 0) { BN_bn2bin(my_key->n, (tui8*)lmod); ssl_reverse_it(lmod, mod_len); } if (error == 0) { len = BN_num_bytes(my_key->d); error = len != pri_len; } if (error == 0) { BN_bn2bin(my_key->d, (tui8*)lpri); ssl_reverse_it(lpri, pri_len); } if (error == 0) { g_memcpy(mod, lmod, mod_len); g_memcpy(pri, lpri, pri_len); } RSA_free(my_key); g_free(lmod); g_free(lpri); return error; } #else /*****************************************************************************/ /* returns error generates a new rsa key exp is passed in and mod and pri are passed out */ int APP_CC ssl_gen_key_xrdp1(int key_size_in_bits, char* exp, int exp_len, char* mod, int mod_len, char* pri, int pri_len) { BIGNUM* my_e; RSA* my_key; char* lexp; char* lmod; char* lpri; int error; int len; if ((exp_len != 4) || (mod_len != 64) || (pri_len != 64)) { return 1; } lexp = (char*)g_malloc(exp_len, 0); lmod = (char*)g_malloc(mod_len, 0); lpri = (char*)g_malloc(pri_len, 0); g_memcpy(lexp, exp, exp_len); ssl_reverse_it(lexp, exp_len); my_e = BN_new(); BN_bin2bn((tui8*)lexp, exp_len, my_e); my_key = RSA_new(); error = RSA_generate_key_ex(my_key, key_size_in_bits, my_e, 0) == 0; if (error == 0) { len = BN_num_bytes(my_key->n); error = len != mod_len; } if (error == 0) { BN_bn2bin(my_key->n, (tui8*)lmod); ssl_reverse_it(lmod, mod_len); } if (error == 0) { len = BN_num_bytes(my_key->d); error = len != pri_len; } if (error == 0) { BN_bn2bin(my_key->d, (tui8*)lpri); ssl_reverse_it(lpri, pri_len); } if (error == 0) { g_memcpy(mod, lmod, mod_len); g_memcpy(pri, lpri, pri_len); } BN_free(my_e); RSA_free(my_key); g_free(lexp); g_free(lmod); g_free(lpri); return error; } #endif xrdp-0.6.0/common/ssl_calls.h000066400000000000000000000035701203155130500161120ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2004-2010 */ #if !defined(SSL_CALLS_H) #define SSL_CALLS_H #include "arch.h" int ssl_init(void); int ssl_finish(void); void* APP_CC ssl_rc4_info_create(void); void APP_CC ssl_rc4_info_delete(void* rc4_info); void APP_CC ssl_rc4_set_key(void* rc4_info, char* key, int len); void APP_CC ssl_rc4_crypt(void* rc4_info, char* data, int len); void* APP_CC ssl_sha1_info_create(void); void APP_CC ssl_sha1_info_delete(void* sha1_info); void APP_CC ssl_sha1_clear(void* sha1_info); void APP_CC ssl_sha1_transform(void* sha1_info, char* data, int len); void APP_CC ssl_sha1_complete(void* sha1_info, char* data); void* APP_CC ssl_md5_info_create(void); void APP_CC ssl_md5_info_delete(void* md5_info); void APP_CC ssl_md5_clear(void* md5_info); void APP_CC ssl_md5_transform(void* md5_info, char* data, int len); void APP_CC ssl_md5_complete(void* md5_info, char* data); int APP_CC ssl_mod_exp(char* out, int out_len, char* in, int in_len, char* mod, int mod_len, char* exp, int exp_len); int APP_CC ssl_gen_key_xrdp1(int key_size_in_bits, char* exp, int exp_len, char* mod, int mod_len, char* pri, int pri_len); #endif xrdp-0.6.0/common/thread_calls.c000066400000000000000000000114651203155130500165550ustar00rootroot00000000000000/* Copyright (c) 2004-2010 Jay Sorg Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. thread calls */ #if defined(_WIN32) #include #else #include #include #endif #include "arch.h" #include "thread_calls.h" #include "os_calls.h" /*****************************************************************************/ /* returns error */ #if defined(_WIN32) int APP_CC tc_thread_create(unsigned long (__stdcall * start_routine)(void*), void* arg) { int rv = 0; DWORD thread_id = 0; HANDLE thread = (HANDLE)0; /* CreateThread returns handle or zero on error */ thread = CreateThread(0, 0, start_routine, arg, 0, &thread_id); rv = !thread; CloseHandle(thread); return rv; } #else int APP_CC tc_thread_create(void* (* start_routine)(void *), void* arg) { int rv = 0; pthread_t thread = (pthread_t)0; g_memset(&thread, 0x00, sizeof(pthread_t)); /* pthread_create returns error */ rv = pthread_create(&thread, 0, start_routine, arg); if (!rv) { rv = pthread_detach(thread); } return rv; } #endif /*****************************************************************************/ tbus APP_CC tc_get_threadid(void) { #if defined(_WIN32) return (tbus)GetCurrentThreadId(); #else return (tbus)pthread_self(); #endif } /*****************************************************************************/ /* returns boolean */ int APP_CC tc_threadid_equal(tbus tid1, tbus tid2) { #if defined(_WIN32) return tid1 == tid2; #else return pthread_equal((pthread_t)tid1, (pthread_t)tid2); #endif } /*****************************************************************************/ tbus APP_CC tc_mutex_create(void) { #if defined(_WIN32) return (tbus)CreateMutex(0, 0, 0); #else pthread_mutex_t* lmutex; lmutex = (pthread_mutex_t*)g_malloc(sizeof(pthread_mutex_t), 0); pthread_mutex_init(lmutex, 0); return (tbus)lmutex; #endif } /*****************************************************************************/ void APP_CC tc_mutex_delete(tbus mutex) { #if defined(_WIN32) CloseHandle((HANDLE)mutex); #else pthread_mutex_t* lmutex; lmutex = (pthread_mutex_t*)mutex; pthread_mutex_destroy(lmutex); g_free(lmutex); #endif } /*****************************************************************************/ int APP_CC tc_mutex_lock(tbus mutex) { #if defined(_WIN32) WaitForSingleObject((HANDLE)mutex, INFINITE); return 0; #else pthread_mutex_lock((pthread_mutex_t*)mutex); return 0; #endif } /*****************************************************************************/ int APP_CC tc_mutex_unlock(tbus mutex) { int rv = 0; #if defined(_WIN32) ReleaseMutex((HANDLE)mutex); #else if (mutex != 0) { rv = pthread_mutex_unlock((pthread_mutex_t *)mutex); } #endif return rv; } /*****************************************************************************/ tbus APP_CC tc_sem_create(int init_count) { #if defined(_WIN32) HANDLE sem; sem = CreateSemaphore(0, init_count, init_count + 10, 0); return (tbus)sem; #else sem_t * sem = (sem_t *)NULL; sem = (sem_t *)g_malloc(sizeof(sem_t), 0); sem_init(sem, 0, init_count); return (tbus)sem; #endif } /*****************************************************************************/ void APP_CC tc_sem_delete(tbus sem) { #if defined(_WIN32) CloseHandle((HANDLE)sem); #else sem_t* lsem; lsem = (sem_t*)sem; sem_destroy(lsem); g_free(lsem); #endif } /*****************************************************************************/ int APP_CC tc_sem_dec(tbus sem) { #if defined(_WIN32) WaitForSingleObject((HANDLE)sem, INFINITE); return 0; #else sem_wait((sem_t*)sem); return 0; #endif } /*****************************************************************************/ int APP_CC tc_sem_inc(tbus sem) { #if defined(_WIN32) ReleaseSemaphore((HANDLE)sem, 1, 0); return 0; #else sem_post((sem_t*)sem); return 0; #endif } xrdp-0.6.0/common/thread_calls.h000066400000000000000000000032231203155130500165530ustar00rootroot00000000000000/* Copyright (c) 2004-2010 Jay Sorg Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. thread calls */ #if !defined(THREAD_CALLS_H) #define THREAD_CALLS_H #include "arch.h" int APP_CC tc_thread_create(THREAD_RV (THREAD_CC * start_routine)(void*), void* arg); tbus APP_CC tc_get_threadid(void); int APP_CC tc_threadid_equal(tbus tid1, tbus tid2); tbus APP_CC tc_mutex_create(void); void APP_CC tc_mutex_delete(tbus mutex); int APP_CC tc_mutex_lock(tbus mutex); int APP_CC tc_mutex_unlock(tbus mutex); tbus APP_CC tc_sem_create(int init_count); void APP_CC tc_sem_delete(tbus sem); int APP_CC tc_sem_dec(tbus sem); int APP_CC tc_sem_inc(tbus sem); #endif xrdp-0.6.0/common/trans.c000066400000000000000000000236061203155130500152570ustar00rootroot00000000000000/* Copyright (c) 2008-2010 Jay Sorg Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. generic transport */ #include "os_calls.h" #include "trans.h" #include "arch.h" #include "parse.h" /*****************************************************************************/ struct trans* APP_CC trans_create(int mode, int in_size, int out_size) { struct trans* self = (struct trans *)NULL; self = (struct trans*)g_malloc(sizeof(struct trans), 1); if (self != NULL) { make_stream(self->in_s); init_stream(self->in_s, in_size); make_stream(self->out_s); init_stream(self->out_s, out_size); self->mode = mode; } return self; } /*****************************************************************************/ void APP_CC trans_delete(struct trans* self) { if (self == 0) { return; } free_stream(self->in_s); free_stream(self->out_s); if (self->sck > 0) { g_tcp_close(self->sck); } self->sck = 0; if (self->listen_filename != 0) { g_file_delete(self->listen_filename); g_free(self->listen_filename); } g_free(self); } /*****************************************************************************/ int APP_CC trans_get_wait_objs(struct trans* self, tbus* objs, int* count, int* timeout) { if (self == 0) { return 1; } if (self->status != TRANS_STATUS_UP) { return 1; } objs[*count] = self->sck; (*count)++; return 0; } /*****************************************************************************/ int APP_CC trans_check_wait_objs(struct trans* self) { tbus in_sck = (tbus)0; struct trans* in_trans = (struct trans *)NULL; int read_bytes = 0; int to_read = 0; int read_so_far = 0; int rv = 0; if (self == 0) { return 1; } if (self->status != TRANS_STATUS_UP) { return 1; } rv = 0; if (self->type1 == TRANS_TYPE_LISTENER) /* listening */ { if (g_tcp_can_recv(self->sck, 0)) { in_sck = g_tcp_accept(self->sck); if (in_sck == -1) { if (g_tcp_last_error_would_block(self->sck)) { /* ok, but shouldn't happen */ } else { /* error */ self->status = TRANS_STATUS_DOWN; return 1; } } if (in_sck != -1) { if (self->trans_conn_in != 0) /* is function assigned */ { in_trans = trans_create(self->mode, self->in_s->size, self->out_s->size); in_trans->sck = in_sck; in_trans->type1 = TRANS_TYPE_SERVER; in_trans->status = TRANS_STATUS_UP; if (self->trans_conn_in(self, in_trans) != 0) { trans_delete(in_trans); } } else { g_tcp_close(in_sck); } } } } else /* connected server or client (2 or 3) */ { if (g_tcp_can_recv(self->sck, 0)) { read_so_far = (int)(self->in_s->end - self->in_s->data); to_read = self->header_size - read_so_far; if (to_read > 0) { read_bytes = g_tcp_recv(self->sck, self->in_s->end, to_read, 0); if (read_bytes == -1) { if (g_tcp_last_error_would_block(self->sck)) { /* ok, but shouldn't happen */ } else { /* error */ self->status = TRANS_STATUS_DOWN; return 1; } } else if (read_bytes == 0) { /* error */ self->status = TRANS_STATUS_DOWN; return 1; } else { self->in_s->end += read_bytes; } } read_so_far = (int)(self->in_s->end - self->in_s->data); if (read_so_far == self->header_size) { if (self->trans_data_in != 0) { rv = self->trans_data_in(self); init_stream(self->in_s, 0); } } } } return rv; } /*****************************************************************************/ int APP_CC trans_force_read_s(struct trans* self, struct stream* in_s, int size) { int rcvd; if (self->status != TRANS_STATUS_UP) { return 1; } while (size > 0) { rcvd = g_tcp_recv(self->sck, in_s->end, size, 0); if (rcvd == -1) { if (g_tcp_last_error_would_block(self->sck)) { if (!g_tcp_can_recv(self->sck, 10)) { /* check for term here */ } } else { /* error */ self->status = TRANS_STATUS_DOWN; return 1; } } else if (rcvd == 0) { /* error */ self->status = TRANS_STATUS_DOWN; return 1; } else { in_s->end += rcvd; size -= rcvd; } } return 0; } /*****************************************************************************/ int APP_CC trans_force_read(struct trans* self, int size) { return trans_force_read_s(self, self->in_s, size); } /*****************************************************************************/ int APP_CC trans_force_write_s(struct trans* self, struct stream* out_s) { int size; int total; int sent; if (self->status != TRANS_STATUS_UP) { return 1; } size = (int)(out_s->end - out_s->data); total = 0; while (total < size) { sent = g_tcp_send(self->sck, out_s->data + total, size - total, 0); if (sent == -1) { if (g_tcp_last_error_would_block(self->sck)) { if (!g_tcp_can_send(self->sck, 10)) { /* check for term here */ } } else { /* error */ self->status = TRANS_STATUS_DOWN; return 1; } } else if (sent == 0) { /* error */ self->status = TRANS_STATUS_DOWN; return 1; } else { total = total + sent; } } return 0; } /*****************************************************************************/ int APP_CC trans_force_write(struct trans* self) { return trans_force_write_s(self, self->out_s); } /*****************************************************************************/ int APP_CC trans_connect(struct trans* self, const char* server, const char* port, int timeout) { int error; if (self->sck != 0) { g_tcp_close(self->sck); } if (self->mode == TRANS_MODE_TCP) /* tcp */ { self->sck = g_tcp_socket(); g_tcp_set_non_blocking(self->sck); error = g_tcp_connect(self->sck, server, port); } else if (self->mode == TRANS_MODE_UNIX) /* unix socket */ { self->sck = g_tcp_local_socket(); g_tcp_set_non_blocking(self->sck); error = g_tcp_local_connect(self->sck, port); } else { self->status = TRANS_STATUS_DOWN; return 1; } if (error == -1) { if (g_tcp_last_error_would_block(self->sck)) { if (g_tcp_can_send(self->sck, timeout)) { self->status = TRANS_STATUS_UP; /* ok */ self->type1 = TRANS_TYPE_CLIENT; /* client */ return 0; } } return 1; } self->status = TRANS_STATUS_UP; /* ok */ self->type1 = TRANS_TYPE_CLIENT; /* client */ return 0; } /*****************************************************************************/ int APP_CC trans_listen_address(struct trans* self, char* port, const char* address) { if (self->sck != 0) { g_tcp_close(self->sck); } if (self->mode == TRANS_MODE_TCP) /* tcp */ { self->sck = g_tcp_socket(); g_tcp_set_non_blocking(self->sck); if (g_tcp_bind_address(self->sck, port, address) == 0) { if (g_tcp_listen(self->sck) == 0) { self->status = TRANS_STATUS_UP; /* ok */ self->type1 = TRANS_TYPE_LISTENER; /* listener */ return 0; } } } else if (self->mode == TRANS_MODE_UNIX) /* unix socket */ { g_free(self->listen_filename); self->listen_filename = 0; g_file_delete(port); self->sck = g_tcp_local_socket(); g_tcp_set_non_blocking(self->sck); if (g_tcp_local_bind(self->sck, port) == 0) { self->listen_filename = g_strdup(port); if (g_tcp_listen(self->sck) == 0) { g_chmod_hex(port, 0xffff); self->status = TRANS_STATUS_UP; /* ok */ self->type1 = TRANS_TYPE_LISTENER; /* listener */ return 0; } } } return 1; } /*****************************************************************************/ int APP_CC trans_listen(struct trans* self, char* port) { return trans_listen_address(self, port, "0.0.0.0"); } /*****************************************************************************/ struct stream* APP_CC trans_get_in_s(struct trans* self) { struct stream * rv = (struct stream *)NULL; if (self == NULL) { rv = (struct stream *)NULL; } else { rv = self->in_s; } return rv; } /*****************************************************************************/ struct stream* APP_CC trans_get_out_s(struct trans* self, int size) { struct stream * rv = (struct stream *)NULL; if (self == NULL) { rv = (struct stream *)NULL; } else { init_stream(self->out_s, size); rv = self->out_s; } return rv; } xrdp-0.6.0/common/trans.h000066400000000000000000000053601203155130500152610ustar00rootroot00000000000000/* Copyright (c) 2008-2010 Jay Sorg Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. generic transport */ #if !defined(TRANS_H) #define TRANS_H #include "arch.h" #include "parse.h" #define TRANS_MODE_TCP 1 #define TRANS_MODE_UNIX 2 #define TRANS_TYPE_LISTENER 1 #define TRANS_TYPE_SERVER 2 #define TRANS_TYPE_CLIENT 3 #define TRANS_STATUS_DOWN 0 #define TRANS_STATUS_UP 1 struct trans; /* forward declaration */ typedef int (*ttrans_data_in)(struct trans* self); typedef int (*ttrans_conn_in)(struct trans* self, struct trans* new_self); struct trans { tbus sck; int mode; /* 1 tcp, 2 unix socket */ int status; int type1; /* 1 listener 2 server 3 client */ ttrans_data_in trans_data_in; ttrans_conn_in trans_conn_in; void* callback_data; int header_size; struct stream* in_s; struct stream* out_s; char* listen_filename; }; struct trans* APP_CC trans_create(int mode, int in_size, int out_size); void APP_CC trans_delete(struct trans* self); int APP_CC trans_get_wait_objs(struct trans* self, tbus* objs, int* count, int* timeout); int APP_CC trans_check_wait_objs(struct trans* self); int APP_CC trans_force_read_s(struct trans* self, struct stream* in_s, int size); int APP_CC trans_force_write_s(struct trans* self, struct stream* out_s); int APP_CC trans_force_read(struct trans* self, int size); int APP_CC trans_force_write(struct trans* self); int APP_CC trans_connect(struct trans* self, const char* server, const char* port, int timeout); int APP_CC trans_listen_address(struct trans* self, char* port, const char* address); int APP_CC trans_listen(struct trans* self, char* port); struct stream* APP_CC trans_get_in_s(struct trans* self); struct stream* APP_CC trans_get_out_s(struct trans* self, int size); #endif xrdp-0.6.0/common/xrdp_constants.h000066400000000000000000000400351203155130500172010ustar00rootroot00000000000000/* rdesktop: A Remote Desktop Protocol client. Miscellaneous protocol constants Copyright (C) Matthew Chapman 1999-2008 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. */ /* modified for xrdp */ #if !defined(XRDP_CONSTANTS_H) #define XRDP_CONSTANTS_H /* TCP port for Remote Desktop Protocol */ #define TCP_PORT_RDP 3389 #define ISO_PDU_CR 0xE0 /* Connection Request */ #define ISO_PDU_CC 0xD0 /* Connection Confirm */ #define ISO_PDU_DR 0x80 /* Disconnect Request */ #define ISO_PDU_DT 0xF0 /* Data */ #define ISO_PDU_ER 0x70 /* Error */ /* MCS PDU codes */ #define MCS_EDRQ 1 /* Erect Domain Request */ #define MCS_DPUM 8 /* Disconnect Provider Ultimatum */ #define MCS_AURQ 10 /* Attach User Request */ #define MCS_AUCF 11 /* Attach User Confirm */ #define MCS_CJRQ 14 /* Channel Join Request */ #define MCS_CJCF 15 /* Channel Join Confirm */ #define MCS_SDRQ 25 /* Send Data Request */ #define MCS_SDIN 26 /* Send Data Indication */ #define MCS_CONNECT_INITIAL 0x7f65 #define MCS_CONNECT_RESPONSE 0x7f66 #define BER_TAG_BOOLEAN 1 #define BER_TAG_INTEGER 2 #define BER_TAG_OCTET_STRING 4 #define BER_TAG_RESULT 10 #define MCS_TAG_DOMAIN_PARAMS 0x30 #define MCS_GLOBAL_CHANNEL 1003 #define MCS_USERCHANNEL_BASE 1001 /* RDP secure transport constants */ #define SEC_RANDOM_SIZE 32 #define SEC_MODULUS_SIZE 64 #define SEC_PADDING_SIZE 8 #define SEC_EXPONENT_SIZE 4 #define SEC_CLIENT_RANDOM 0x0001 #define SEC_ENCRYPT 0x0008 #define SEC_LOGON_INFO 0x0040 #define SEC_LICENCE_NEG 0x0080 #define SEC_TAG_SRV_INFO 0x0c01 #define SEC_TAG_SRV_CRYPT 0x0c02 #define SEC_TAG_SRV_CHANNELS 0x0c03 #define SEC_TAG_CLI_INFO 0xc001 #define SEC_TAG_CLI_CRYPT 0xc002 #define SEC_TAG_CLI_CHANNELS 0xc003 #define SEC_TAG_CLI_4 0xc004 #define SEC_TAG_PUBKEY 0x0006 #define SEC_TAG_KEYSIG 0x0008 #define SEC_RSA_MAGIC 0x31415352 /* RSA1 */ /* RDP licensing constants */ #define LICENCE_TOKEN_SIZE 10 #define LICENCE_HWID_SIZE 20 #define LICENCE_SIGNATURE_SIZE 16 #define LICENCE_TAG_DEMAND 0x01 #define LICENCE_TAG_AUTHREQ 0x02 #define LICENCE_TAG_ISSUE 0x03 #define LICENCE_TAG_REISSUE 0x04 #define LICENCE_TAG_PRESENT 0x12 #define LICENCE_TAG_REQUEST 0x13 #define LICENCE_TAG_AUTHRESP 0x15 #define LICENCE_TAG_RESULT 0xff #define LICENCE_TAG_USER 0x000f #define LICENCE_TAG_HOST 0x0010 /* RDP PDU codes */ #define RDP_PDU_DEMAND_ACTIVE 1 #define RDP_PDU_CONFIRM_ACTIVE 3 #define RDP_PDU_REDIRECT 4 #define RDP_PDU_DEACTIVATE 6 #define RDP_PDU_DATA 7 #define RDP_DATA_PDU_UPDATE 2 #define RDP_DATA_PDU_CONTROL 20 #define RDP_DATA_PDU_POINTER 27 #define RDP_DATA_PDU_INPUT 28 #define RDP_DATA_PDU_SYNCHRONISE 31 #define RDP_DATA_PDU_PLAY_SOUND 34 #define RDP_DATA_PDU_LOGON 38 #define RDP_DATA_PDU_FONT2 39 #define RDP_DATA_PDU_DISCONNECT 47 #define RDP_CTL_REQUEST_CONTROL 1 #define RDP_CTL_GRANT_CONTROL 2 #define RDP_CTL_DETACH 3 #define RDP_CTL_COOPERATE 4 #define RDP_UPDATE_ORDERS 0 #define RDP_UPDATE_BITMAP 1 #define RDP_UPDATE_PALETTE 2 #define RDP_UPDATE_SYNCHRONIZE 3 #define RDP_POINTER_SYSTEM 1 #define RDP_POINTER_MOVE 3 #define RDP_POINTER_COLOR 6 #define RDP_POINTER_CACHED 7 #define RDP_NULL_POINTER 0 #define RDP_DEFAULT_POINTER 0x7F00 #define RDP_INPUT_SYNCHRONIZE 0 #define RDP_INPUT_CODEPOINT 1 #define RDP_INPUT_VIRTKEY 2 #define RDP_INPUT_SCANCODE 4 #define RDP_INPUT_MOUSE 0x8001 /* Device flags */ #define KBD_FLAG_RIGHT 0x0001 #define KBD_FLAG_EXT 0x0100 #define KBD_FLAG_QUIET 0x1000 #define KBD_FLAG_DOWN 0x4000 #define KBD_FLAG_UP 0x8000 /* These are for synchronization; not for keystrokes */ #define KBD_FLAG_SCROLL 0x0001 #define KBD_FLAG_NUMLOCK 0x0002 #define KBD_FLAG_CAPITAL 0x0004 /* See T.128 */ #define RDP_KEYPRESS 0 #define RDP_KEYRELEASE (KBD_FLAG_DOWN | KBD_FLAG_UP) #define MOUSE_FLAG_MOVE 0x0800 #define MOUSE_FLAG_BUTTON1 0x1000 #define MOUSE_FLAG_BUTTON2 0x2000 #define MOUSE_FLAG_BUTTON3 0x4000 #define MOUSE_FLAG_BUTTON4 0x0280 #define MOUSE_FLAG_BUTTON5 0x0380 #define MOUSE_FLAG_DOWN 0x8000 /* Raster operation masks */ #define ROP2_S(rop3) (rop3 & 0xf) #define ROP2_P(rop3) ((rop3 & 0x3) | ((rop3 & 0x30) >> 2)) #define ROP2_COPY 0xc #define ROP2_XOR 0x6 #define ROP2_AND 0x8 #define ROP2_NXOR 0x9 #define ROP2_OR 0xe #define MIX_TRANSPARENT 0 #define MIX_OPAQUE 1 #define TEXT2_VERTICAL 0x04 #define TEXT2_IMPLICIT_X 0x20 /* RDP bitmap cache (version 2) constants */ #define BMPCACHE2_C0_CELLS 0x78 #define BMPCACHE2_C1_CELLS 0x78 #define BMPCACHE2_C2_CELLS 0x150 #define BMPCACHE2_NUM_PSTCELLS 0x9f6 #define PDU_FLAG_FIRST 0x01 #define PDU_FLAG_LAST 0x02 /* Maps to generalCapabilitySet in T.128 page 138 */ /* RDP capabilities */ #define RDP_CAPSET_GENERAL 1 #define RDP_CAPLEN_GENERAL 0x18 #define OS_MAJOR_TYPE_UNIX 4 #define OS_MINOR_TYPE_XSERVER 7 #define RDP_CAPSET_BITMAP 2 #define RDP_CAPLEN_BITMAP 0x1C #define RDP_CAPSET_ORDER 3 #define RDP_CAPLEN_ORDER 0x58 #define ORDER_CAP_NEGOTIATE 2 #define ORDER_CAP_NOSUPPORT 4 #define RDP_CAPSET_BMPCACHE 4 #define RDP_CAPLEN_BMPCACHE 0x28 #define RDP_CAPSET_CONTROL 5 #define RDP_CAPLEN_CONTROL 0x0C #define RDP_CAPSET_ACTIVATE 7 #define RDP_CAPLEN_ACTIVATE 0x0C #define RDP_CAPSET_POINTER 8 #define RDP_CAPLEN_POINTER 0x0a #define RDP_CAPLEN_POINTER_MONO 0x08 #define RDP_CAPSET_SHARE 9 #define RDP_CAPLEN_SHARE 0x08 #define RDP_CAPSET_COLCACHE 10 #define RDP_CAPLEN_COLCACHE 0x08 #define RDP_CAPSET_INPUT 13 #define RDP_CAPLEN_INPUT 0x58 #define RDP_CAPSET_FONT 14 #define RDP_CAPLEN_FONT 0x04 #define RDP_CAPSET_BRUSHCACHE 15 #define RDP_CAPLEN_BRUSHCACHE 0x08 #define RDP_CAPSET_BITMAP_OFFSCREEN 18 #define RDP_CAPLEN_BITMAP_OFFSCREEN 0x08 #define RDP_CAPSET_BMPCACHE2 19 #define RDP_CAPLEN_BMPCACHE2 0x28 #define BMPCACHE2_FLAG_PERSIST ((long)1<<31) #define RDP_CAPSET_VIRCHAN 20 #define RDP_CAPLEN_VIRCHAN 0x08 #define RDP_SOURCE "MSTSC" /* Logon flags */ #define RDP_LOGON_AUTO 0x0008 #define RDP_LOGON_NORMAL 0x0033 #define RDP_COMPRESSION 0x0080 #define RDP_LOGON_BLOB 0x0100 #define RDP_LOGON_LEAVE_AUDIO 0x2000 #define RDP5_DISABLE_NOTHING 0x00 #define RDP5_NO_WALLPAPER 0x01 #define RDP5_NO_FULLWINDOWDRAG 0x02 #define RDP5_NO_MENUANIMATIONS 0x04 #define RDP5_NO_THEMING 0x08 #define RDP5_NO_CURSOR_SHADOW 0x20 #define RDP5_NO_CURSORSETTINGS 0x40 /* disables cursor blinking */ /* compression types */ #define RDP_MPPC_COMPRESSED 0x20 #define RDP_MPPC_RESET 0x40 #define RDP_MPPC_FLUSH 0x80 #define RDP_MPPC_DICT_SIZE 8192 /* Keymap flags */ #define MapRightShiftMask (1 << 0) #define MapLeftShiftMask (1 << 1) #define MapShiftMask (MapRightShiftMask | MapLeftShiftMask) #define MapRightAltMask (1 << 2) #define MapLeftAltMask (1 << 3) #define MapAltGrMask MapRightAltMask #define MapRightCtrlMask (1 << 4) #define MapLeftCtrlMask (1 << 5) #define MapCtrlMask (MapRightCtrlMask | MapLeftCtrlMask) #define MapRightWinMask (1 << 6) #define MapLeftWinMask (1 << 7) #define MapWinMask (MapRightWinMask | MapLeftWinMask) #define MapNumLockMask (1 << 8) #define MapCapsLockMask (1 << 9) #define MapLocalStateMask (1 << 10) #define MapInhibitMask (1 << 11) #define MASK_ADD_BITS(var, mask) (var |= mask) #define MASK_REMOVE_BITS(var, mask) (var &= ~mask) #define MASK_HAS_BITS(var, mask) ((var & mask)>0) #define MASK_CHANGE_BIT(var, mask, active) \ (var = ((var & ~mask) | (active ? mask : 0))) /* Clipboard constants, "borrowed" from GCC system headers in the w32 cross compiler */ #define CF_TEXT 1 #define CF_BITMAP 2 #define CF_METAFILEPICT 3 #define CF_SYLK 4 #define CF_DIF 5 #define CF_TIFF 6 #define CF_OEMTEXT 7 #define CF_DIB 8 #define CF_PALETTE 9 #define CF_PENDATA 10 #define CF_RIFF 11 #define CF_WAVE 12 #define CF_UNICODETEXT 13 #define CF_ENHMETAFILE 14 #define CF_HDROP 15 #define CF_LOCALE 16 #define CF_MAX 17 #define CF_OWNERDISPLAY 128 #define CF_DSPTEXT 129 #define CF_DSPBITMAP 130 #define CF_DSPMETAFILEPICT 131 #define CF_DSPENHMETAFILE 142 #define CF_PRIVATEFIRST 512 #define CF_PRIVATELAST 767 #define CF_GDIOBJFIRST 768 #define CF_GDIOBJLAST 1023 /* Sound format constants */ #define WAVE_FORMAT_PCM 1 #define WAVE_FORMAT_ADPCM 2 #define WAVE_FORMAT_ALAW 6 #define WAVE_FORMAT_MULAW 7 /* Virtual channel options */ #define CHANNEL_OPTION_INITIALIZED 0x80000000 #define CHANNEL_OPTION_ENCRYPT_RDP 0x40000000 #define CHANNEL_OPTION_COMPRESS_RDP 0x00800000 #define CHANNEL_OPTION_SHOW_PROTOCOL 0x00200000 /* NT status codes for RDPDR */ #define STATUS_SUCCESS 0x00000000 #define STATUS_PENDING 0x00000103 #define STATUS_NO_MORE_FILES 0x80000006 #define STATUS_DEVICE_PAPER_EMPTY 0x8000000e #define STATUS_DEVICE_POWERED_OFF 0x8000000f #define STATUS_DEVICE_OFF_LINE 0x80000010 #define STATUS_DEVICE_BUSY 0x80000011 #define STATUS_INVALID_HANDLE 0xc0000008 #define STATUS_INVALID_PARAMETER 0xc000000d #define STATUS_NO_SUCH_FILE 0xc000000f #define STATUS_INVALID_DEVICE_REQUEST 0xc0000010 #define STATUS_ACCESS_DENIED 0xc0000022 #define STATUS_OBJECT_NAME_COLLISION 0xc0000035 #define STATUS_DISK_FULL 0xc000007f #define STATUS_FILE_IS_A_DIRECTORY 0xc00000ba #define STATUS_NOT_SUPPORTED 0xc00000bb #define STATUS_TIMEOUT 0xc0000102 #define STATUS_CANCELLED 0xc0000120 /* RDPDR constants */ #define RDPDR_MAX_DEVICES 0x10 #define DEVICE_TYPE_SERIAL 0x01 #define DEVICE_TYPE_PARALLEL 0x02 #define DEVICE_TYPE_PRINTER 0x04 #define DEVICE_TYPE_DISK 0x08 #define DEVICE_TYPE_SCARD 0x20 #define FILE_DIRECTORY_FILE 0x00000001 #define FILE_NON_DIRECTORY_FILE 0x00000040 #define FILE_OPEN_FOR_FREE_SPACE_QUERY 0x00800000 /* RDP5 disconnect PDU */ #define exDiscReasonNoInfo 0x0000 #define exDiscReasonAPIInitiatedDisconnect 0x0001 #define exDiscReasonAPIInitiatedLogoff 0x0002 #define exDiscReasonServerIdleTimeout 0x0003 #define exDiscReasonServerLogonTimeout 0x0004 #define exDiscReasonReplacedByOtherConnection 0x0005 #define exDiscReasonOutOfMemory 0x0006 #define exDiscReasonServerDeniedConnection 0x0007 #define exDiscReasonServerDeniedConnectionFips 0x0008 #define exDiscReasonLicenseInternal 0x0100 #define exDiscReasonLicenseNoLicenseServer 0x0101 #define exDiscReasonLicenseNoLicense 0x0102 #define exDiscReasonLicenseErrClientMsg 0x0103 #define exDiscReasonLicenseHwidDoesntMatchLicense 0x0104 #define exDiscReasonLicenseErrClientLicense 0x0105 #define exDiscReasonLicenseCantFinishProtocol 0x0106 #define exDiscReasonLicenseClientEndedProtocol 0x0107 #define exDiscReasonLicenseErrClientEncryption 0x0108 #define exDiscReasonLicenseCantUpgradeLicense 0x0109 #define exDiscReasonLicenseNoRemoteConnections 0x010a #define RDP_ORDER_STANDARD 0x01 #define RDP_ORDER_SECONDARY 0x02 #define RDP_ORDER_BOUNDS 0x04 #define RDP_ORDER_CHANGE 0x08 #define RDP_ORDER_DELTA 0x10 #define RDP_ORDER_LASTBOUNDS 0x20 #define RDP_ORDER_SMALL 0x40 #define RDP_ORDER_TINY 0x80 #define RDP_ORDER_DESTBLT 0 #define RDP_ORDER_PATBLT 1 #define RDP_ORDER_SCREENBLT 2 #define RDP_ORDER_LINE 9 #define RDP_ORDER_RECT 10 #define RDP_ORDER_DESKSAVE 11 #define RDP_ORDER_MEMBLT 13 #define RDP_ORDER_TRIBLT 14 #define RDP_ORDER_POLYLINE 22 #define RDP_ORDER_TEXT2 27 #define RDP_ORDER_RAW_BMPCACHE 0 #define RDP_ORDER_COLCACHE 1 #define RDP_ORDER_BMPCACHE 2 #define RDP_ORDER_FONTCACHE 3 #define RDP_ORDER_RAW_BMPCACHE2 4 #define RDP_ORDER_BMPCACHE2 5 #define RDP_ORDER_BRUSHCACHE 7 /* drawable types */ #define WND_TYPE_BITMAP 0 #define WND_TYPE_WND 1 #define WND_TYPE_SCREEN 2 #define WND_TYPE_BUTTON 3 #define WND_TYPE_IMAGE 4 #define WND_TYPE_EDIT 5 #define WND_TYPE_LABEL 6 #define WND_TYPE_COMBO 7 #define WND_TYPE_SPECIAL 8 #define WND_TYPE_LISTBOX 9 /* button states */ #define BUTTON_STATE_UP 0 #define BUTTON_STATE_DOWN 1 /* messages */ #define WM_PAINT 3 #define WM_KEYDOWN 15 #define WM_KEYUP 16 #define WM_MOUSEMOVE 100 #define WM_LBUTTONUP 101 #define WM_LBUTTONDOWN 102 #define WM_RBUTTONUP 103 #define WM_RBUTTONDOWN 104 #define WM_BUTTON3UP 105 #define WM_BUTTON3DOWN 106 #define WM_BUTTON4UP 107 #define WM_BUTTON4DOWN 108 #define WM_BUTTON5UP 109 #define WM_BUTTON5DOWN 110 #define WM_INVALIDATE 200 #define CB_ITEMCHANGE 300 #endif xrdp-0.6.0/configure.ac000066400000000000000000000070341203155130500147570ustar00rootroot00000000000000# Process this file with autoconf to produce a configure script AC_PREREQ(2.59) AC_INIT([xrdp], [0.6.0], [xrdp-devel@lists.sourceforge.net]) AM_CONFIG_HEADER(config_ac.h:config_ac-h.in) AM_INIT_AUTOMAKE([1.6 foreign]) AC_PROG_CC AC_C_CONST AC_PROG_LIBTOOL AC_ARG_ENABLE(nopam, AS_HELP_STRING([--enable-nopam], [Build no PAM support (default: no)]), [nopam=true], [nopam=false]) AM_CONDITIONAL(SESMAN_NOPAM, [test x$nopam = xtrue]) AC_ARG_ENABLE(kerberos, AS_HELP_STRING([--enable-kerberos], [Build kerberos support (default: no)]), [kerberos=true], [kerberos=false]) AM_CONDITIONAL(SESMAN_KERBEROS, [test x$kerberos = xtrue]) AC_ARG_ENABLE(pamuserpass, AS_HELP_STRING([--enable-pamuserpass], [Build pam userpass support (default: no)]), [pamuserpass=true], [pamuserpass=false]) AM_CONDITIONAL(SESMAN_PAMUSERPASS, [test x$pamuserpass = xtrue]) AC_ARG_ENABLE(xrdpdebug, AS_HELP_STRING([--enable-xrdpdebug], [Build debug (default: no)]), [xrdpdebug=true], [xrdpdebug=false]) AM_CONDITIONAL(XRDP_DEBUG, [test x$xrdpdebug = xtrue]) AC_ARG_ENABLE(freerdp, AS_HELP_STRING([--enable-freerdp], [Build freerdp module (default: no)]), [freerdp=true], [freerdp=false]) AM_CONDITIONAL(XRDP_FREERDP, [test x$freerdp = xtrue]) AC_ARG_ENABLE(freerdp1, AS_HELP_STRING([--enable-freerdp1], [Build freerdp1 module (default: no)]), [freerdp1=true], [freerdp1=false]) AM_CONDITIONAL(XRDP_FREERDP1, [test x$freerdp1 = xtrue]) # checking for openssl AC_CHECK_HEADER([openssl/rc4.h], [], [AC_MSG_ERROR([please install libssl-dev or openssl-devel])], [#include ]) # checking if pam should be autodetected. if test -z "$enable_nopam" then if test -z "$enable_kerberos" then AC_CHECK_HEADER([security/pam_appl.h], [], [AC_MSG_ERROR([please install libpam0g-dev or pam-devel])]) fi fi AS_IF( [test "x$enable_freerdp" = "xyes"] , [PKG_CHECK_MODULES(FREERDP, freerdp >= 0.8.1)] ) AS_IF( [test "x$enable_freerdp1" = "xyes"] , [PKG_CHECK_MODULES(FREERDP, freerdp >= 1.0.0)] ) # checking for Xlib, Xfixes AC_CHECK_HEADER([X11/Xlib.h], [], [AC_MSG_ERROR([please install libx11-dev or libX11-devel])]) AC_CHECK_HEADER([X11/extensions/Xfixes.h], [], [AC_MSG_ERROR([please install libx11-dev and libxfixes-dev or libXfixes-devel])], [#include ]) libdir="${libdir}/xrdp"; if test "x${prefix}" = "xNONE" ; then sysconfdir="/etc"; localstatedir="/var"; fi AC_CONFIG_FILES([Makefile common/Makefile vnc/Makefile rdp/Makefile libxrdp/Makefile xup/Makefile mc/Makefile freerdp/Makefile freerdp1/Makefile xrdp/Makefile sesman/Makefile sesman/libscp/Makefile sesman/tools/Makefile sesman/sessvc/Makefile sesman/chansrv/Makefile keygen/Makefile docs/Makefile docs/man/Makefile instfiles/Makefile instfiles/pam.d/Makefile genkeymap/Makefile ]) # fontdump/Makefile # xrdp/cursors/Makefile # Xserver/hw/rdp/Makefile AC_OUTPUT # example of how to check for a struct in a header #AC_CHECK_MEMBER([struct in6_addr.s6_addr], # [], # [AC_DEFINE(NO_ARPA_INET_H_IP6, 1, [for IPv6])], # [#include ]) xrdp-0.6.0/design.txt000066400000000000000000000022621203155130500145010ustar00rootroot00000000000000 This document is intended to explain xrdp server design. Many connections, all capable of running different modules one connection could be using a vnc connection one could be running a custom app made for xrdp one could be running a X11 session clients control the screen size and color depth all controlled by a configuration file. you can create a lib or use a lib with your executable that talks to xrdp server. ------ ---------- -xrdp---linked-------mylib.so- session 1 ------ ---------- | | ------------------------- |----unix socket--myapp linked to libxrdp- session 2 | ------------------------- | | ----------- |----linked-------mylib2.so- session 3 ----------- Any of the above sessions can repeat or have different session numbers or not even be used. If a session is disconnected, all that changes is the rdp connection is lost, the session remains. For X11, start the XServer after the user is authenticated. First check for the next available X11 display, create a user session, start the XServer and set the DISPLAY enviromenet variable. xrdp-0.6.0/docs/000077500000000000000000000000001203155130500134155ustar00rootroot00000000000000xrdp-0.6.0/docs/Makefile.am000066400000000000000000000000231203155130500154440ustar00rootroot00000000000000 SUBDIRS = \ man xrdp-0.6.0/docs/man/000077500000000000000000000000001203155130500141705ustar00rootroot00000000000000xrdp-0.6.0/docs/man/Makefile.am000066400000000000000000000003611203155130500162240ustar00rootroot00000000000000EXTRA_DIST = sesman.ini.5 xrdp.ini.5 xrdp.8 xrdp-sesman.8 xrdp-sesrun.8 xrdpman5dir=$(mandir)/man5 xrdpman5_DATA = \ sesman.ini.5 \ xrdp.ini.5 xrdpman8dir=$(mandir)/man8 xrdpman8_DATA = \ xrdp.8 \ xrdp-sesman.8 \ xrdp-sesrun.8 xrdp-0.6.0/docs/man/sesman.ini.5000066400000000000000000000134401203155130500163240ustar00rootroot00000000000000.\" .TH "sesman.ini" "5" "0.1.0" "xrdp team" "" .SH "NAME" .LP \fBsesman.ini\fR \- Configuration file for \fBsesman\fR(8) .SH "DESCRIPTION" .LP This is the man page for \fBsesman.ini\fR, \fBsesman\fR(8) configuration file. It is composed by a number of sections, each one composed by a section name, enclosed by square brackets, folowed by a list of \fI\fR=\fI\fR lines. \fBsesman.ini\fR supports the following sections: .TP \fB[Globals]\fR \- sesman global configuration section, .TP \fB[Logging]\fR \- logging subsystem parameters .TP \fB[Security]\fR \- Access control parameters .TP \fB[Sessions]\fR \- Session management parameters .LP All options and values (except for file names and paths) are case insensitive, and are described in detail below. .LP For any of the following parameter, if it's specified more than one time the last entry encountered will be used. \fBNOTE\fR: if any of these options is specified outside its section, it will be \fIignored\fR. .SH "GLOBALS" .LP .TP The options to be specified in the \fB[globals]\fR section are the following: .br .TP \fBListenAddress\fR=\fIip address\fR Specifies sesman listening address. Default is 0.0.0.0 (all interfaces) .br .TP \fBListenPort\fR=\fIport number\fR Specifies sesman listening port. Default is 3350 .br .TP \fBEnableUserWindowManager\fR=\fI[0|1]\fR If set to \fB1\fR, \fBtrue\fR or \fByes\fR this option enables user specific window manager, that is, anyone can define it's own script executed by sesman when starting a new session, specified by \fBUserWindowManager\fR .br .TP \fBUserWindowManager\fR=\fIstartwm.sh\fR This option specifies the script run by sesman when starting a session and per\-user window manager is enabled. .br The path is relative to user's HOME directory .br .TP \fBDefaultWindowManager\fR=\fI${SESMAN_BIN_DIR}/startwm.sh\fR This contains full path to the default window manager startup script used by sesman to start a session .SH "LOGGING" .LP .TP The following parameters can be used in the \fB[logging]\fR section: .br .TP \fBLogFile\fR=\fI${SESMAN_LOG_DIR}/sesman.log\fR This options contains the path to logfile. It can be either absolute or relative, and the default is \fI${SESMAN_LOG_DIR}/sesman.log\fR .br .TP \fBLogLevel\fR=\fIlevel\fR This option can have one of the following values: \fBCORE\fR or \fB0\fR \- Log only core messages. these messages are _always_ logged, regardless the logging level selected. \fBERROR\fR or \fB1\fR \- Log only error messages \fBWARNING\fR, \fBWARN\fR or \fB2\fR \- Logs warnings and error messages \fBINFO\fR or \fB3\fR \- Logs errors, warnings and informational messages \fBDEBUG\fR or \fB4\fR \- Log everything. If \fBsesman\fR is compiled in debug mode, this options will output many more low\-level message, useful for developers .br .TP \fBEnableSyslog\fR=\fI[0|1]\fR If set to \fB1\fR, \fBtrue\fR or \fByes\fR this option enables logging to syslog. Otherwise syslog is disabled. .br .TP \fBSyslogLevel\fR=\fIlevel\fR This option sets the logging level for syslog. It can have the same values of \fBLogLevel\fR. If \fBSyslogLevel\fR is greater than \fBLogLevel\fR, its value is lowered to that of \fBLogLevel\fR. .SH "SESSIONS" .LP .TP The following parameters can be used in the \fB[Sessions]\fR section: .br .TP \fBX11DisplayOffset\fR=\fI\fR Specifies the first X display number available for sesman(8). This prevents sesman from interfering with real X11 servers. The default is 10. .br .TP \fBMaxSessions\fR=\fI\fR Sets the maximum number of simultaneous session on terminal server. .br If unset or set to \fI0\fR, unlimited session are allowed. .br .TP \fBKillDisconnected\fR=\fI[0|1]\fR If set to \fB1\fR, \fBtrue\fR or \fByes\fR, every session will be killed when the user disconnects. .br \fI\-this option is currently ignored!\-\fR .br .TP \fBIdleTimeLimit\fR=\fI\fR Sets the the time limit before an idle session is disconnected. .br If set to \fI0\fR, automatic disconnection is disabled. .br \fI\-this option is currently ignored!\-\fR .br .TP \fBDisconnectedTimeLimit\fR=\fI\fR Sets the the time limit before a disconnected session is killed. .br If set to \fI0\fR, automatic killing is disabled. .br \fI\-this option is currently ignored!\-\fR .br .SH "SECURITY" .LP .TP The following parameters can be used in the \fB[Sessions]\fR section: .br .TP \fBAllowRootLogin\fR=\fI[0|1]\fR If set to \fB1\fR, \fBtrue\fR or \fByes\fR enables root login on the terminal server .br .TP \fBMaxLoginRetry\fR=\fI[0|1]\fR The number of login attempts that are allowed on terminal server. If set to \fI0\fR, unlimited attempts are allowed. The default value for this field is \fI3\fR. .br .TP \fBTerminalServerUsers\fR=\fItsusers\fR Only the users belonging to the group \fItsusers\fR are allowed to login on terminal server. .br If unset or set to an invalid or non\-existent group, login for all users is enabled. .br .TP \fBTerminalServerAdmins\fR=\fItsadmins\fR Sets the group which a user shall belong to have session management rights. .br \fI\-this option is currently ignored!\-\fR .br .SH "EXAMPLES" .LP This is an example \fBsesman.ini\fR: [Globals] .br ListenAddress=127.0.0.1 .br ListenPort=3350 .br EnableUserWindowManager=1 .br UserWindowManager=startwm.sh .br DefaultWindowManager=startwm.sh [Logging] .br LogFile=/usr/local/xrdp/sesman.log .br LogLevel=DEBUG .br EnableSyslog=0 .br SyslogLevel=DEBUG [Sessions] .br MaxSessions=10 .br KillDisconnected=0 .br IdleTimeLimit=0 .br DisconnectedTimeLimit=0 [Security] .br AllowRootLogin=1 .br MaxLoginRetry=3 .br TerminalServerUsers=tsusers .br TerminalServerAdmins=tsadmins .SH "FILES" .LP ${SESMAN_CFG_DIR}/sesman.ini .SH "SEE ALSO" .LP sesman(8) sesrun(8) xrdp(8) xrdp.ini(5) for more info on \fBxrdp\fR see http://xrdp.sf.net xrdp-0.6.0/docs/man/xrdp-sesman.8000066400000000000000000000017331203155130500165260ustar00rootroot00000000000000.TH "sesman" "8" "0.1.0" "xrdp team" "" .SH "NAME" .LP \fBsesman\fR \- \fBxrdp\fR(8) session manager .SH "SYNTAX" .LP sesman [ \-\-nodaemon | \-\-kill | \-\-help ] .SH "DESCRIPTION" .LP \fBsesman\fR is \fBxrdp\fR(8) session manager. .br It manages user sessions by authenticating the user and starting the appropriate Xserver .SH "OPTIONS" .LP .TP \fB\-n\fR, \fB\-\-nodaemon\fR Starts \fBsesman\fR in foreground instead of starting it as a daemon. .TP \fB\-k\fR, \fB\-\-kill\fR Kills running \fBsesman\fR daemon. .TP \fB\-h\fR, \fB\-\-help\fR Output help information and exit. .SH "FILES" .LP ${SESMAN_BIN_DIR}/sesman .br ${SESMAN_BIN_DIR}/sesrun .br ${SESMAN_CFG_DIR}/sesman.ini .br ${SESMAN_LOG_DIR}/sesman.log .br ${SESMAN_PID_DIR}/sesman.pid .SH "AUTHORS" .LP Jay Sorg .br Simone Fedele .SH "SEE ALSO" .LP sesman.ini(5) sesrun(8) xrdp(8) xrdp.ini(5) for more info on \fBxrdp\fR see http://xrdp.sf.net xrdp-0.6.0/docs/man/xrdp-sesrun.8000066400000000000000000000016721203155130500165610ustar00rootroot00000000000000.TH "sesrun" "8" "0.1.0" "xrdp team" "" .SH "NAME" .LP \fBsesrun\fR \- \fBsesman\fR(8) session launcher .SH "SYNTAX" .LP sesrun .SH "DESCRIPTION" .LP \fBsesrun\fR starts a session using \fBsesman\fR(8). .br This is a tool useful for testing, it simply behaves like xrdp when some user logs in a new session and authenticates, thus starting a new session. .SH "OPTIONS" .LP .TP Server on which sesman is running .TP user name of the session being started .TP user password .TP Screen width .TP Screen height .TP Session color depth .SH "FILES" .LP ${SESMAN_BIN_DIR}/sesman .br ${SESMAN_BIN_DIR}/sesrun .SH "AUTHORS" .LP Jay Sorg .br Simone Fedele .SH "SEE ALSO" .LP sesman(8) sesman.ini(5) xrdp(8) xrdp.ini(5) for more info on \fBxrdp\fR see http://xrdp.sf.net xrdp-0.6.0/docs/man/xrdp.8000066400000000000000000000017761203155130500152510ustar00rootroot00000000000000.TH "xrdp" "8" "0.1.0" "xrdp team" "" .SH "NAME" .LP \fBxrdp\fR \- a Remote Desktop Protocol (RDP) server .SH "SYNTAX" .LP xrdp [ \-\-nodaemon | \-\-kill | \-\-help ] .SH "DESCRIPTION" .LP \fBxrdp\fR is a Remote Desktop Protocol (RDP) Server. .br Unlike Windows NT/2000/2003 server, \fBxrdp\fR will not display a Windows desktop but an X window desktop to the user. It can also be used as a VNC\->RDP bridge. .SH "OPTIONS" .LP .TP \fB\-n\fR, \fB\-\-nodaemon\fR Starts \fBxrdp\fR in foreground instead of starting it as a daemon. .TP \fB\-k\fR, \fB\-\-kill\fR Kills running \fBxrdp\fR daemon. .TP \fB\-h\fR, \fB\-\-help\fR Output help information and exit. .SH "FILES" .LP ${XRDP_BIN_DIR}/xrdp .br ${XRDP_CFG_DIR}/xrdp.ini .br ${XRDP_LOG_DIR}/xrdp.log .br ${XRDP_PID_DIR}/xrdp.pid .SH "AUTHORS" .LP Jay Sorg .br Simone Fedele .SH "SEE ALSO" .LP xrdp.ini(5) sesman(8) sesman.ini(5) sesrun(8) for more info on \fBxrdp\fR see http://xrdp.sf.net xrdp-0.6.0/docs/man/xrdp.ini.5000066400000000000000000000046501203155130500160160ustar00rootroot00000000000000.\" .TH "xrdp.ini" "5" "0.1.0" "xrdp team" "" .SH "NAME" .LP \fBxrdp.ini\fR \- Configuration file for \fBxrdp\fR(8) .SH "DESCRIPTION" .LP This is the man page for \fBxrdp.ini\fR, \fBxrdp\fR(8) configuration file. It is composed by a number of sections, each one composed by a section name, enclosed by square brackets, folowed by a list of \fI\fR=\fI\fR lines. \fBxrdp.ini\fR is contains a \fB[Globals]\fR section, which sets some global configuration settings for \fBxrdp\fR(8), and one or more "connection" sections which contain the info on which services \fBxrdp\fR(8) can connect to. .LP All options and values (except for file names and paths) are case insensitive, and are described in detail below. .SH "GLOBALS" .LP .TP The options to be specified in the \fB[Globals]\fR section are the following: .br .TP \fBbitmap_cache\fR=\fI[0|1]\fR If set to \fB1\fR, \fBtrue\fR or \fByes\fR this option enables bitmap caching in \fBxrdp\fR(8) .br .TP \fBbitmap_compression\fR=\fI[0|1]\fR If set to \fB1\fR, \fBtrue\fR or \fByes\fR this option enables bitmap compression in \fBxrdp\fR(8) .SH "CONNECTIONS" .LP .TP A connection section is made of a section name, enclosed in square brackets, and the following entries: .br .TP \fBname\fR=\fI\fR The name displayed in \fBxrdp\fR(8) login window's combo box. .br .TP \fBlib\fR=\fI../vnc/libvnc.so\fR Sets the library to be used with this connection. .br .TP \fBusername\fR=\fI\fR|\fIask\fR Specifies the username used for authenticating in the connection. If set to \fIask\fR, user name should be provided in the login window. .br .TP \fBpassword\fR=\fI\fR|\fIask\fR Specifies the password used for authenticating in the connection. If set to \fIask\fR, password should be provided in the login window. .br .TP \fBip\fR=\fI127.0.0.1\fR Specifies the ip address of the host to connect to. .br .TP \fBport\fR=\fI\fR|\fI\-1\fR Specifies the port number to connect to. If set to \fI\-1\fR, the default port for the specified library is used. .SH "EXAMPLES" .LP This is an example \fBxrdp.ini\fR: [Globals] .br bitmap_cache=yes .br bitmap_compression=yes [vnc1] .br name=sesman .br lib=../vnc/libvnc.so .br username=ask .br password=ask .br ip=127.0.0.1 .br port=\-1 .SH "FILES" .LP ${XRDP_CFG_DIR}/xrdp.ini .SH "SEE ALSO" .LP xrdp(8) sesman(8) sesrun(8) sesman.ini(5) for more info on \fBxrdp\fR see http://xrdp.sf.net xrdp-0.6.0/faq-compile.txt000066400000000000000000000010551203155130500154240ustar00rootroot00000000000000Compile FAQ Q. I get error: security/pam_appl.h: File or directory doesn't exist What is wrong? A. You need to install pam development package. For Debian / Ubuntu this package is called libpam0g-dev. For Red Hat / Suse this package is called pam-devel. Q. I get error : A. You need to install opensll development package. For Debian / Ubuntu this package is called libssl-dev. For Red Hat / Suze this package is called openssl-devel. Q. A.i Red Hat libX11-devel libXfixes-devel Debian libx11-dev libxfixes-dev xrdp-0.6.0/faq-general.txt000066400000000000000000000005611203155130500154120ustar00rootroot00000000000000General FAQ Q. What is RDP? A. RDP stands for Remote Desktop Protocol. Its the protocol used by Windows terminal servers to talk to the terminal server clients. Q. What is xrdp? A. xrdp, usually spell lower case, is as open source implementation of the RDP protocol. Q. I can't get it to compile in Ubuntu. What can I do? A. See faq-compile.txt. xrdp-0.6.0/file-loc.txt000066400000000000000000000014061203155130500147210ustar00rootroot00000000000000 default build will install the following /usr/local/lib/xrdp/ libcommon.so libmc.so librdp.so libscp.so libvnc.so libxrdp.so libxup.so /usr/local/bin/ xrdp-genkeymap xrdp-keygen xrdp-sesadmin xrdp-sesrun xrdp-sestest /usr/local/sbin/ xrdp xrdp-sesman xrdp-sessvc xrdp-chansrv /etc/xrdp/ km-xxxx.ini sesman.ini rsakeys.ini startwm.sh xrdp.ini xrdp.sh /etc/pam.d/ xrdp-sesman /usr/local/share/man/man5 sesman.ini.5 xrdp.ini.5 /usr/local/share/man/man8 xrdp.8 xrdp-sesman.8 xrdp-sesrun.8 /usr/local/share/xrdp ad256.bmp cursor0.cur cursor1.cur sans-10.fv1 xrdp256.bmp when running, the following are created and written to /var/run/ xrdp.pid sesman.pid /var/log/ xrdp-sesman.log /tmp xrdp* xrdp-0.6.0/fontdump/000077500000000000000000000000001203155130500143215ustar00rootroot00000000000000xrdp-0.6.0/fontdump/Makefile000077500000000000000000000004721203155130500157670ustar00rootroot00000000000000 OBJS = fontdump.obj os_calls.obj #CFLAGS = -O2 -I../common CFLAGS = -O2 -I../common -DUNICODE -D_UNICODE LDFLAGS = -W -efontdump.exe all: fontdump1 fontdump1: $(OBJS) $(CC) $(LDFLAGS) $(OBJS) clean: del $(OBJS) fontdump.exe *.tds os_calls.obj: ../common/os_calls.c $(CC) $(CFLAGS) -c ../common/os_calls.c xrdp-0.6.0/fontdump/fontdump.c000077500000000000000000000267301203155130500163340ustar00rootroot00000000000000 #include #include #include #include #include #include #include "os_calls.h" #include "arch.h" static HINSTANCE g_instance = 0; static HWND g_wnd = 0; static HWND g_lb = 0; static HWND g_exit_button = 0; static HWND g_go_button = 0; static HWND g_font_list = 0; static char g_font_name[512] = ""; static int g_font_size = 10; static HFONT g_font = 0; static int g_running = 0; #define FONT_DATASIZE(_w, _h) (((_h * ((_w + 7) / 8)) + 3) & ~3) /*****************************************************************************/ int check_messages(void) { MSG msg; while (PeekMessage(&msg, 0, 0, 0, PM_NOREMOVE)) { GetMessage(&msg, NULL, 0, 0); TranslateMessage(&msg); DispatchMessage(&msg); } return 0; } /*****************************************************************************/ static int msg(char* msg1, ...) { va_list ap; char text1[512]; va_start(ap, msg1); vsnprintf(text1, 511, msg1, ap); SendMessageA(g_lb, LB_ADDSTRING, 0, (LPARAM)text1); va_end(ap); return 0; } /*****************************************************************************/ static int show_last_error(void) { LPVOID lpMsgBuf; FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&lpMsgBuf, 0, NULL); msg("GetLastError - %s", lpMsgBuf); LocalFree(lpMsgBuf); return 0; } /*****************************************************************************/ static int font_dump(void) { HDC dc; HDC dc1; RECT rect; HBRUSH brush; HGDIOBJ saved; HBITMAP bitmap; BITMAPINFO bi; char* bits; ABC abc; SIZE sz; char filename[256]; TCHAR text[256]; char zero1; char* bmtext; int bmtextindex; int fd; int x1; int strlen1; int index1; int index2; int len; int pixel; int red; int green; int blue; int width; int height; int roller; int outlen; tui8 b1; short x2; if (g_running) { return 0; } g_running = 1; msg("starting"); g_font_name[0] = 0; SendMessageA(g_font_list, WM_GETTEXT, 255, (LPARAM)g_font_name); if (g_strlen(g_font_name) == 0) { msg("error font not set"); g_running = 0; return 1; } dc = GetDC(g_wnd); height = -MulDiv(g_font_size, GetDeviceCaps(dc, LOGPIXELSY), 72); g_font = CreateFontA(height, 0, 0, 0, FW_DONTCARE, 0, 0, 0, 0, 0, 0, 0, 0, g_font_name); ReleaseDC(g_wnd, dc); if (g_font == 0) { msg("error - Font creation failed"); } zero1 = 0; g_snprintf(filename, 255, "%s-%d.fv1", g_font_name, g_font_size); msg("creating file %s", filename); g_file_delete(filename); fd = g_file_open(filename); g_file_write(fd, "FNT1", 4); strlen1 = g_strlen(g_font_name); g_file_write(fd, g_font_name, strlen1); x1 = strlen1; while (x1 < 32) { g_file_write(fd, &zero1, 1); x1++; } x2 = g_font_size; /* font size */ g_file_write(fd, (char*)&x2, 2); x2 = 1; /* style */ g_file_write(fd, (char*)&x2, 2); /* pad */ index1 = 0; while (index1 < 8) { g_file_write(fd, &zero1, 1); index1++; } for (x1 = 32; x1 < 0x4e00; x1++) { check_messages(); dc = GetWindowDC(g_wnd); saved = SelectObject(dc, g_font); if (!GetCharABCWidths(dc, x1, x1, &abc)) { show_last_error(); } text[0] = (TCHAR)x1; text[1] = 0; if (!GetTextExtentPoint32(dc, text, 1, &sz)) { show_last_error(); } SelectObject(dc, saved); ReleaseDC(g_wnd, dc); if ((sz.cx > 0) && (sz.cy > 0)) { dc = GetWindowDC(g_wnd); saved = SelectObject(dc, g_font); SetBkColor(dc, RGB(255, 255, 255)); if (!ExtTextOut(dc, 50, 50, ETO_OPAQUE, 0, text, 1, 0)) { show_last_error(); } SelectObject(dc, saved); ReleaseDC(g_wnd, dc); Sleep(10); /* width */ x2 = abc.abcB; g_file_write(fd, (char*)&x2, 2); /* height */ x2 = sz.cy; g_file_write(fd, (char*)&x2, 2); /* baseline */ x2 = -sz.cy; g_file_write(fd, (char*)&x2, 2); /* offset */ x2 = abc.abcA; g_file_write(fd, (char*)&x2, 2); /* incby */ x2 = sz.cx; g_file_write(fd, (char*)&x2, 2); /* pad */ index1 = 0; while (index1 < 6) { g_file_write(fd, &zero1, 1); index1++; } dc = GetWindowDC(g_wnd); rect.left = 50 + abc.abcA; rect.top = 50; rect.right = rect.left + abc.abcB; rect.bottom = rect.top + sz.cy; memset(&bi, 0, sizeof(bi)); width = (abc.abcB + 7) & (~7); height = sz.cy; bi.bmiHeader.biSize = sizeof(bi.bmiHeader); bi.bmiHeader.biWidth = width; bi.bmiHeader.biHeight = height; bi.bmiHeader.biPlanes = 1; bi.bmiHeader.biBitCount = 32; bitmap = CreateDIBSection(dc, &bi, DIB_RGB_COLORS, (void*)&bits, 0, 0); if (bitmap == 0) { msg("error - CreateDIBSection failed"); } else { memset(bits, 0, width * height * 4); dc1 = CreateCompatibleDC(dc); SelectObject(dc1, bitmap); if (!BitBlt(dc1, 0, 0, width, height, dc, rect.left, rect.top, SRCCOPY)) { show_last_error(); } bmtext = (char*)g_malloc(width * height + 16, 1); bmtextindex = 0; for (index1 = (height - 1); index1 >= 0; index1--) { for (index2 = 0; index2 < width; index2++) { pixel = ((int*)bits)[index1 * width + index2]; red = (pixel >> 16) & 0xff; green = (pixel >> 8) & 0xff; blue = (pixel >> 0) & 0xff; if (red == 0 && green == 0 && blue == 0) { bmtext[bmtextindex] = '1'; bmtextindex++; } else { bmtext[bmtextindex] = '0'; bmtextindex++; } } } outlen = 0; b1 = 0; roller = 0; len = g_strlen(bmtext); for (index2 = 0; index2 < len; index2++) { if (bmtext[index2] == '1') { switch (roller) { case 0: b1 = b1 | 0x80; break; case 1: b1 = b1 | 0x40; break; case 2: b1 = b1 | 0x20; break; case 3: b1 = b1 | 0x10; break; case 4: b1 = b1 | 0x08; break; case 5: b1 = b1 | 0x04; break; case 6: b1 = b1 | 0x02; break; case 7: b1 = b1 | 0x01; break; } } roller++; if (roller == 8) { roller = 0; g_file_write(fd, &b1, 1); outlen++; b1 = 0; } } while ((outlen % 4) != 0) { g_file_write(fd, &zero1, 1); outlen++; } free(bmtext); DeleteDC(dc1); DeleteObject(bitmap); } if (sz.cx != (long)(abc.abcA + abc.abcB + abc.abcC)) { msg("error - width not right 1"); } brush = CreateSolidBrush(RGB(255, 255, 255)); FillRect(dc, &rect, brush); DeleteObject(brush); ReleaseDC(g_wnd, dc); } else { /* write out a blank glyph here */ /* width */ x2 = 1; g_file_write(fd, (char*)&x2, 2); /* height */ x2 = 1; g_file_write(fd, (char*)&x2, 2); /* baseline */ x2 = 0; g_file_write(fd, (char*)&x2, 2); /* offset */ x2 = 0; g_file_write(fd, (char*)&x2, 2); /* incby */ x2 = 1; g_file_write(fd, (char*)&x2, 2); /* pad */ index1 = 0; while (index1 < 6) { g_file_write(fd, &zero1, 1); index1++; } /* blank bitmap */ index1 = 0; while (index1 < 4) { g_file_write(fd, &zero1, 1); index1++; } } } g_file_close(fd); msg("done"); g_running = 0; return 0; } /*****************************************************************************/ static LRESULT CALLBACK wnd_proc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { PAINTSTRUCT ps; HBRUSH brush; RECT rect; switch (message) { case WM_PAINT: BeginPaint(hWnd, &ps); brush = CreateSolidBrush(RGB(255, 255, 255)); rect = ps.rcPaint; FillRect(ps.hdc, &rect, brush); DeleteObject(brush); EndPaint(hWnd, &ps); break; case WM_CLOSE: DestroyWindow(g_wnd); g_wnd = 0; break; case WM_DESTROY: PostQuitMessage(0); break; case WM_TIMER: KillTimer(g_wnd, 1); font_dump(); break; case WM_COMMAND: if ((HWND)lParam == g_exit_button) { PostMessage(g_wnd, WM_CLOSE, 0, 0); } else if ((HWND)lParam == g_go_button) { while (SendMessage(g_lb, LB_GETCOUNT, 0, 0) > 0) { SendMessage(g_lb, LB_DELETESTRING, 0, 0); } SetTimer(g_wnd, 1, 1000, 0); } break; } return DefWindowProc(hWnd, message, wParam, lParam); } /*****************************************************************************/ static int create_window(void) { WNDCLASS wc; DWORD style; HDC dc; int height; int left; int top; ZeroMemory(&wc, sizeof(wc)); wc.lpfnWndProc = wnd_proc; /* points to window procedure */ /* name of window class */ wc.lpszClassName = _T("fontdump"); wc.hCursor = LoadCursor(0, IDC_ARROW); /* Register the window class. */ if (!RegisterClass(&wc)) { return 0; /* Failed to register window class */ } style = WS_OVERLAPPED | WS_CAPTION | WS_POPUP | WS_MINIMIZEBOX | WS_SYSMENU | WS_SIZEBOX | WS_MAXIMIZEBOX; left = GetSystemMetrics(SM_CXSCREEN) / 2 - 640 / 2; top = GetSystemMetrics(SM_CYSCREEN) / 2 - 480 / 2; g_wnd = CreateWindow(wc.lpszClassName, _T("fontdump"), style, left, top, 640, 480, (HWND) NULL, (HMENU) NULL, g_instance, (LPVOID) NULL); style = WS_CHILD | WS_VISIBLE | WS_BORDER; g_lb = CreateWindow(_T("LISTBOX"), _T("LISTBOX1"), style, 200, 10, 400, 400, g_wnd, 0, g_instance, 0); style = WS_CHILD | WS_VISIBLE; g_exit_button = CreateWindow(_T("BUTTON"), _T("Exit"), style, 540, 410, 75, 25, g_wnd, 0, g_instance, 0); g_go_button = CreateWindow(_T("BUTTON"), _T("Go"), style, 440, 410, 75, 25, g_wnd, 0, g_instance, 0); style = WS_CHILD | WS_VISIBLE | CBS_DROPDOWN; g_font_list = CreateWindow(_T("COMBOBOX"), _T("COMBOBOX1"), style, 50, 250, 125, 125, g_wnd, 0, g_instance, 0); ShowWindow(g_wnd, SW_SHOWNORMAL); PostMessage(g_wnd, WM_SETFONT, (WPARAM)g_font, 0); SendMessageA(g_font_list, CB_ADDSTRING, 0, (LPARAM)"Tahoma"); SendMessageA(g_font_list, CB_ADDSTRING, 0, (LPARAM)"DejaVu Serif"); SendMessageA(g_font_list, CB_ADDSTRING, 0, (LPARAM)"DejaVu Sans"); SendMessageA(g_font_list, CB_ADDSTRING, 0, (LPARAM)"Arial"); SendMessageA(g_font_list, CB_ADDSTRING, 0, (LPARAM)"Comic Sans MS"); return 0; } /*****************************************************************************/ static int main_loop(void) { MSG msg; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return (int)(msg.wParam); } /*****************************************************************************/ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { g_instance = hInstance; create_window(); return main_loop(); } xrdp-0.6.0/freerdp/000077500000000000000000000000001203155130500141145ustar00rootroot00000000000000xrdp-0.6.0/freerdp/Makefile.am000066400000000000000000000007041203155130500161510ustar00rootroot00000000000000EXTRA_DIST = xrdp-freerdp.h AM_CFLAGS = \ -DXRDP_CFG_PATH=\"${sysconfdir}/xrdp\" \ -DXRDP_SBIN_PATH=\"${sbindir}\" \ -DXRDP_SHARE_PATH=\"${datadir}/xrdp\" \ -DXRDP_PID_PATH=\"${localstatedir}/run\" INCLUDES = \ -I$(top_srcdir)/common \ $(FREERDP_CFLAGS) lib_LTLIBRARIES = \ libxrdpfreerdp.la libxrdpfreerdp_la_SOURCES = xrdp-freerdp.c xrdp-color.c libxrdpfreerdp_la_LIBADD = \ $(top_srcdir)/common/libcommon.la \ $(FREERDP_LIBS) xrdp-0.6.0/freerdp/xrdp-color.c000066400000000000000000000142551203155130500163600ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2010 freerdp wrapper */ #include "xrdp-freerdp.h" char* APP_CC convert_bitmap(int in_bpp, int out_bpp, char* bmpdata, int width, int height, int* palette) { char* out; char* src; char* dst; int i; int j; int red; int green; int blue; int pixel; if ((in_bpp == 8) && (out_bpp == 8)) { out = (char*)g_malloc(width * height, 0); src = bmpdata; dst = out; for (i = 0; i < height; i++) { for (j = 0; j < width; j++) { pixel = *((tui8*)src); pixel = palette[pixel]; SPLITCOLOR32(red, green, blue, pixel); pixel = COLOR8(red, green, blue); *dst = pixel; src++; dst++; } } return out; } if ((in_bpp == 8) && (out_bpp == 16)) { out = (char*)g_malloc(width * height * 2, 0); src = bmpdata; dst = out; for (i = 0; i < height; i++) { for (j = 0; j < width; j++) { pixel = *((tui8*)src); pixel = palette[pixel]; SPLITCOLOR32(red, green, blue, pixel); pixel = COLOR16(red, green, blue); *((tui16*)dst) = pixel; src++; dst += 2; } } return out; } if ((in_bpp == 8) && (out_bpp == 24)) { out = (char*)g_malloc(width * height * 4, 0); src = bmpdata; dst = out; for (i = 0; i < height; i++) { for (j = 0; j < width; j++) { pixel = *((tui8*)src); pixel = palette[pixel]; SPLITCOLOR32(red, green, blue, pixel); pixel = COLOR24RGB(red, green, blue); *((tui32*)dst) = pixel; src++; dst += 4; } } return out; } if ((in_bpp == 15) && (out_bpp == 16)) { out = (char*)g_malloc(width * height * 2, 0); src = bmpdata; dst = out; for (i = 0; i < height; i++) { for (j = 0; j < width; j++) { pixel = *((tui16*)src); SPLITCOLOR15(red, green, blue, pixel); pixel = COLOR16(red, green, blue); *((tui16*)dst) = pixel; src += 2; dst += 2; } } return out; } if ((in_bpp == 15) && (out_bpp == 24)) { out = (char*)g_malloc(width * height * 4, 0); src = bmpdata; dst = out; for (i = 0; i < height; i++) { for (j = 0; j < width; j++) { pixel = *((tui16*)src); SPLITCOLOR15(red, green, blue, pixel); pixel = COLOR24RGB(red, green, blue); *((tui32*)dst) = pixel; src += 2; dst += 4; } } return out; } if ((in_bpp == 16) && (out_bpp == 16)) { return bmpdata; } if ((in_bpp == 16) && (out_bpp == 24)) { out = (char*)g_malloc(width * height * 4, 0); src = bmpdata; dst = out; for (i = 0; i < height; i++) { for (j = 0; j < width; j++) { pixel = *((tui16*)src); SPLITCOLOR16(red, green, blue, pixel); pixel = COLOR24RGB(red, green, blue); *((tui32*)dst) = pixel; src += 2; dst += 4; } } return out; } if ((in_bpp == 24) && (out_bpp == 24)) { out = (char*)g_malloc(width * height * 4, 0); src = bmpdata; dst = out; for (i = 0; i < height; i++) { for (j = 0; j < width; j++) { blue = *((tui8*)src); src++; green = *((tui8*)src); src++; red = *((tui8*)src); src++; pixel = COLOR24RGB(red, green, blue); *((tui32*)dst) = pixel; dst += 4; } } return out; } if ((in_bpp == 32) && (out_bpp == 24)) { return bmpdata; } if ((in_bpp == 32) && (out_bpp == 32)) { return bmpdata; } g_writeln("convert_bitmap: error unknown conversion from %d to %d", in_bpp, out_bpp); return 0; } /*****************************************************************************/ /* returns color or 0 */ int APP_CC convert_color(int in_bpp, int out_bpp, int in_color, int* palette) { int pixel; int red; int green; int blue; if ((in_bpp == 1) && (out_bpp == 24)) { pixel = in_color == 0 ? 0 : 0xffffff; return pixel; } if ((in_bpp == 8) && (out_bpp == 8)) { pixel = palette[in_color]; SPLITCOLOR32(red, green, blue, pixel); pixel = COLOR8(red, green, blue); return pixel; } if ((in_bpp == 8) && (out_bpp == 16)) { pixel = palette[in_color]; SPLITCOLOR32(red, green, blue, pixel); pixel = COLOR16(red, green, blue); return pixel; } if ((in_bpp == 8) && (out_bpp == 24)) { pixel = palette[in_color]; SPLITCOLOR32(red, green, blue, pixel); pixel = COLOR24BGR(red, green, blue); return pixel; } if ((in_bpp == 15) && (out_bpp == 16)) { pixel = in_color; SPLITCOLOR15(red, green, blue, pixel); pixel = COLOR16(red, green, blue); return pixel; } if ((in_bpp == 15) && (out_bpp == 24)) { pixel = in_color; SPLITCOLOR15(red, green, blue, pixel); pixel = COLOR24BGR(red, green, blue); return pixel; } if ((in_bpp == 16) && (out_bpp == 16)) { return in_color; } if ((in_bpp == 16) && (out_bpp == 24)) { pixel = in_color; SPLITCOLOR16(red, green, blue, pixel); pixel = COLOR24BGR(red, green, blue); return pixel; } if ((in_bpp == 24) && (out_bpp == 24)) { return in_color; } if ((in_bpp == 32) && (out_bpp == 24)) { return in_color; } if ((in_bpp == 32) && (out_bpp == 32)) { return in_color; } g_writeln("convert_color: error unknown conversion from %d to %d", in_bpp, out_bpp); return 0; } xrdp-0.6.0/freerdp/xrdp-color.h000066400000000000000000000020071203155130500163550ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2010 */ #ifndef __XRDP_COLOR_H #define __XRDP_COLOR_H char* APP_CC convert_bitmap(int in_bpp, int out_bpp, char* bmpdata, int width, int height, int* palette); int APP_CC convert_color(int in_bpp, int out_bpp, int in_color, int* palette); #endif xrdp-0.6.0/freerdp/xrdp-freerdp.c000066400000000000000000000707761203155130500167030ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2010 freerdp wrapper */ #include "xrdp-freerdp.h" #include "xrdp-color.h" #define GET_MOD(_inst) ((struct mod*)((_inst)->param1)) #define SET_MOD(_inst, _mod) ((_inst)->param1) = _mod struct my_bitmap { char* data; int width; int height; int bpp; }; struct my_cursor { char* andmask; int andbpp; char* xormask; int xorbpp; int width; int height; int hotx; int hoty; }; /*****************************************************************************/ /* return error */ static int DEFAULT_CC lib_mod_start(struct mod* mod, int w, int h, int bpp) { LIB_DEBUG(mod, "in lib_mod_start"); g_writeln("lib_mod_start: w %d h %d bpp %d", w, h, bpp); mod->width = w; mod->height = h; mod->bpp = bpp; if (bpp == 24) { mod->settings->server_depth = 32; } else { mod->settings->server_depth = mod->bpp; } mod->settings->width = mod->width; mod->settings->height = mod->height; LIB_DEBUG(mod, "out lib_mod_start"); return 0; } /******************************************************************************/ /* return error */ static int DEFAULT_CC lib_mod_connect(struct mod* mod) { int code; LIB_DEBUG(mod, "in lib_mod_connect"); code = mod->inst->rdp_connect(mod->inst); g_writeln("lib_mod_connect: code %d", code); LIB_DEBUG(mod, "out lib_mod_connect"); return code; } /******************************************************************************/ /* return error */ static int DEFAULT_CC lib_mod_event(struct mod* mod, int msg, long param1, long param2, long param3, long param4) { LIB_DEBUG(mod, "in lib_mod_event"); int ext; //g_writeln("%d %d %d %d %d", msg, param1, param2, param3, param4); switch (msg) { case 15: ext = param4 & 0x100 ? 1 : 0; mod->inst->rdp_send_input_scancode(mod->inst, 0, ext, param3); break; case 16: ext = param4 & 0x100 ? 1 : 0; mod->inst->rdp_send_input_scancode(mod->inst, 1, ext, param3); break; case 17: mod->inst->rdp_sync_input(mod->inst, param4); break; case 100: mod->inst->rdp_send_input_mouse(mod->inst, PTRFLAGS_MOVE, param1, param2); break; case 101: mod->inst->rdp_send_input_mouse(mod->inst, PTRFLAGS_BUTTON1, param1, param2); break; case 102: mod->inst->rdp_send_input_mouse(mod->inst, PTRFLAGS_BUTTON1 | PTRFLAGS_DOWN, param1, param2); break; case 103: mod->inst->rdp_send_input_mouse(mod->inst, PTRFLAGS_BUTTON2, param1, param2); break; case 104: mod->inst->rdp_send_input_mouse(mod->inst, PTRFLAGS_BUTTON2 | PTRFLAGS_DOWN, param1, param2); break; case 105: mod->inst->rdp_send_input_mouse(mod->inst, PTRFLAGS_BUTTON3, param1, param2); break; case 106: mod->inst->rdp_send_input_mouse(mod->inst, PTRFLAGS_BUTTON3 | PTRFLAGS_DOWN, param1, param2); break; case 107: //mod->inst->rdp_send_input_mouse(mod->inst, // MOUSE_FLAG_BUTTON4, param1, param2); break; case 108: //mod->inst->rdp_send_input_mouse(mod->inst, // MOUSE_FLAG_BUTTON4 | MOUSE_FLAG_DOWN, // param1, param2); break; case 109: //mod->inst->rdp_send_input_mouse(mod->inst, // MOUSE_FLAG_BUTTON5, param1, param2); break; case 110: //mod->inst->rdp_send_input_mouse(mod->inst, // MOUSE_FLAG_BUTTON5 | MOUSE_FLAG_DOWN, // param1, param2); break; } LIB_DEBUG(mod, "out lib_mod_event"); return 0; } /******************************************************************************/ /* return error */ static int DEFAULT_CC lib_mod_signal(struct mod* mod) { LIB_DEBUG(mod, "in lib_mod_signal"); g_writeln("lib_mod_signal:"); LIB_DEBUG(mod, "out lib_mod_signal"); return 0; } /******************************************************************************/ /* return error */ static int DEFAULT_CC lib_mod_end(struct mod* mod) { g_writeln("lib_mod_end:"); return 0; } /******************************************************************************/ /* return error */ static int DEFAULT_CC lib_mod_set_param(struct mod* mod, char* name, char* value) { g_writeln("lib_mod_set_param: name [%s] value [%s]", name, value); if (g_strcmp(name, "hostname") == 0) { g_strncpy(mod->settings->hostname, value, sizeof(mod->settings->hostname)); } else if (g_strcmp(name, "ip") == 0) { g_strncpy(mod->settings->server, value, sizeof(mod->settings->server)); } else if (g_strcmp(name, "port") == 0) { mod->settings->tcp_port_rdp = g_atoi(value); } else if (g_strcmp(name, "keylayout") == 0) { mod->settings->keyboard_layout = g_atoi(value); } else if (g_strcmp(name, "name") == 0) { } else if (g_strcmp(name, "lib") == 0) { } else { g_writeln("lib_mod_set_param: unknown name [%s] value [%s]", name, value); } return 0; } /******************************************************************************/ static int DEFAULT_CC mod_session_change(struct mod* v, int a, int b) { g_writeln("mod_session_change:"); return 0; } /******************************************************************************/ static int DEFAULT_CC mod_get_wait_objs(struct mod* v, tbus* read_objs, int* rcount, tbus* write_objs, int* wcount, int* timeout) { void** rfds; void** wfds; rfds = (void**)read_objs; wfds = (void**)write_objs; return v->inst->rdp_get_fds(v->inst, rfds, rcount, wfds, wcount); } /******************************************************************************/ static int DEFAULT_CC mod_check_wait_objs(struct mod* v) { return v->inst->rdp_check_fds(v->inst); } /******************************************************************************/ static void DEFAULT_CC ui_error(rdpInst* inst, const char* text) { g_writeln("ui_error: %s", text); } /******************************************************************************/ static void DEFAULT_CC ui_warning(rdpInst* inst, const char* text) { g_writeln("ui_warning: %s", text); } /******************************************************************************/ static void DEFAULT_CC ui_unimpl(rdpInst* inst, const char* text) { g_writeln("ui_unimpl: %s", text); } /******************************************************************************/ static void DEFAULT_CC ui_begin_update(rdpInst* inst) { struct mod* mod; mod = GET_MOD(inst); mod->server_begin_update(mod); } /******************************************************************************/ static void DEFAULT_CC ui_end_update(rdpInst* inst) { struct mod* mod; mod = GET_MOD(inst); mod->server_end_update(mod); } /******************************************************************************/ static void DEFAULT_CC ui_desktop_save(rdpInst* inst, int offset, int x, int y, int cx, int cy) { g_writeln("ui_desktop_save:"); } /******************************************************************************/ static void DEFAULT_CC ui_desktop_restore(rdpInst* inst, int offset, int x, int y, int cx, int cy) { g_writeln("ui_desktop_restore:"); } /******************************************************************************/ static RD_HBITMAP DEFAULT_CC ui_create_bitmap(rdpInst* inst, int width, int height, uint8* data) { struct my_bitmap* bm; struct mod* mod; int size; int bpp; char* bmpdata; mod = GET_MOD(inst); bpp = mod->bpp == 24 ? 32 : mod->bpp; bm = (struct my_bitmap*)g_malloc(sizeof(struct my_bitmap), 1); bm->width = width; bm->height = height; bm->bpp = bpp; bmpdata = convert_bitmap(mod->settings->server_depth, bpp, data, width, height, mod->cmap); if (bmpdata == (char*)data) { size = width * height * ((bpp + 7) / 8); bm->data = (char*)g_malloc(size, 0); g_memcpy(bm->data, bmpdata, size); } else { bm->data = bmpdata; } return bm; } /******************************************************************************/ static void DEFAULT_CC ui_paint_bitmap(rdpInst* inst, int x, int y, int cx, int cy, int width, int height, uint8* data) { struct mod* mod; char* bmpdata; mod = GET_MOD(inst); bmpdata = convert_bitmap(mod->settings->server_depth, mod->bpp, data, width, height, mod->cmap); if (bmpdata != 0) { mod->server_paint_rect(mod, x, y, cx, cy, bmpdata, width, height, 0, 0); } if (bmpdata != (char*)data) { g_free(bmpdata); } } /******************************************************************************/ static void DEFAULT_CC ui_destroy_bitmap(rdpInst* inst, RD_HBITMAP bmp) { struct my_bitmap* bm; bm = (struct my_bitmap*)bmp; g_free(bm->data); g_free(bm); } /******************************************************************************/ static void DEFAULT_CC ui_line(rdpInst* inst, uint8 opcode, int startx, int starty, int endx, int endy, RD_PEN* pen) { g_writeln("ui_line:"); } /******************************************************************************/ static void DEFAULT_CC ui_rect(rdpInst* inst, int x, int y, int cx, int cy, uint32 color) { struct mod* mod; mod = GET_MOD(inst); color = convert_color(mod->settings->server_depth, mod->bpp, color, mod->cmap); mod->server_set_fgcolor(mod, color); mod->server_fill_rect(mod, x, y, cx, cy); } /******************************************************************************/ static void DEFAULT_CC ui_polygon(rdpInst* inst, uint8 opcode, uint8 fillmode, RD_POINT* point, int npoints, RD_BRUSH* brush, uint32 bgcolor, uint32 fgcolor) { g_writeln("ui_polygon:"); } /******************************************************************************/ static void DEFAULT_CC ui_polyline(rdpInst* inst, uint8 opcode, RD_POINT* points, int npoints, RD_PEN* pen) { g_writeln("ui_polyline:"); } /******************************************************************************/ static void DEFAULT_CC ui_ellipse(rdpInst* inst, uint8 opcode, uint8 fillmode, int x, int y, int cx, int cy, RD_BRUSH* brush, uint32 bgcolor, uint32 fgcolor) { g_writeln("ui_ellipse:"); } /******************************************************************************/ static void DEFAULT_CC ui_add_char(rdpInst * inst, uint8 font, uint16 character, sint16 offset, sint16 baseline, uint16 width, uint16 height, uint8 * data) { struct mod* mod; //g_writeln("ui_add_char:"); mod = GET_MOD(inst); mod->server_add_char(mod, font, character, offset, baseline, width, height, (char*)data); } /******************************************************************************/ static void DEFAULT_CC ui_draw_text(rdpInst* inst, uint8 font, uint8 flags, uint8 opcode, int mixmode, int x, int y, int clipx, int clipy, int clipcx, int clipcy, int boxx, int boxy, int boxcx, int boxcy, RD_BRUSH * brush, uint32 bgcolor, uint32 fgcolor, uint8 * text, uint8 length) { struct mod* mod; //g_writeln("ui_draw_text: flags %d mixmode %d x %d y %d", flags, mixmode, x, y); //g_writeln("%d %d %d %d %d %d %d %d", clipx, clipy, clipcx, clipcy, boxx, boxy, boxcx, boxcy); mod = GET_MOD(inst); fgcolor = convert_color(mod->settings->server_depth, mod->bpp, fgcolor, mod->cmap); mod->server_set_fgcolor(mod, fgcolor); bgcolor = convert_color(mod->settings->server_depth, mod->bpp, bgcolor, mod->cmap); mod->server_set_bgcolor(mod, bgcolor); mod->server_draw_text(mod, font, flags, mixmode, clipx, clipy, clipx + clipcx, clipy + clipcy, boxx, boxy, boxx + boxcx, boxy + boxcy, x, y, (char*)text, length); } /******************************************************************************/ static void DEFAULT_CC ui_start_draw_glyphs(rdpInst* inst, uint32 bgcolor, uint32 fgcolor) { g_writeln("ui_start_draw_glyphs:"); } /******************************************************************************/ static void DEFAULT_CC ui_draw_glyph(rdpInst* inst, int x, int y, int cx, int cy, RD_HGLYPH glyph) { g_writeln("ui_draw_glyph:"); } /******************************************************************************/ static void DEFAULT_CC ui_end_draw_glyphs(rdpInst* inst, int x, int y, int cx, int cy) { g_writeln("ui_end_draw_glyphs:"); } /******************************************************************************/ static uint32 DEFAULT_CC ui_get_toggle_keys_state(rdpInst* inst) { g_writeln("ui_get_toggle_keys_state:"); return 0; } /******************************************************************************/ static void DEFAULT_CC ui_bell(rdpInst* inst) { g_writeln("ui_bell:"); } /******************************************************************************/ static void DEFAULT_CC ui_destblt(rdpInst* inst, uint8 opcode, int x, int y, int cx, int cy) { struct mod* mod; g_writeln("ui_destblt:"); mod = GET_MOD(inst); mod->server_set_opcode(mod, opcode); mod->server_fill_rect(mod, x, y, cx, cy); mod->server_set_opcode(mod, 0xcc); } /******************************************************************************/ static void DEFAULT_CC ui_patblt(rdpInst* inst, uint8 opcode, int x, int y, int cx, int cy, RD_BRUSH* brush, uint32 bgcolor, uint32 fgcolor) { struct mod* mod; uint8 idata[8]; int index; mod = GET_MOD(inst); mod->server_set_opcode(mod, opcode); fgcolor = convert_color(mod->settings->server_depth, mod->bpp, fgcolor, mod->cmap); mod->server_set_fgcolor(mod, fgcolor); bgcolor = convert_color(mod->settings->server_depth, mod->bpp, bgcolor, mod->cmap); mod->server_set_bgcolor(mod, bgcolor); mod->server_set_mixmode(mod, 1); if (brush->bd != 0) { if (brush->bd->color_code == 1) /* 8x8 1 bpp */ { for (index = 0; index < 8; index++) { idata[index] = ~(brush->bd->data[index]); } mod->server_set_brush(mod, brush->xorigin, brush->yorigin, brush->style, idata); } else { g_writeln("ui_patblt: error color_code %d", brush->bd->color_code); } } else { for (index = 0; index < 8; index++) { idata[index] = ~(brush->pattern[index]); } mod->server_set_brush(mod, brush->xorigin, brush->yorigin, brush->style, idata); } mod->server_fill_rect(mod, x, y, cx, cy); mod->server_set_opcode(mod, 0xcc); mod->server_set_mixmode(mod, 0); } /******************************************************************************/ static void DEFAULT_CC ui_screenblt(rdpInst* inst, uint8 opcode, int x, int y, int cx, int cy, int srcx, int srcy) { struct mod* mod; mod = GET_MOD(inst); mod->server_set_opcode(mod, opcode); mod->server_screen_blt(mod, x, y, cx, cy, srcx, srcy); mod->server_set_opcode(mod, 0xcc); } /******************************************************************************/ static void DEFAULT_CC ui_memblt(rdpInst* inst, uint8 opcode, int x, int y, int cx, int cy, RD_HBITMAP src, int srcx, int srcy) { struct my_bitmap* bitmap; struct mod* mod; char* bmpdata; mod = GET_MOD(inst); bitmap = (struct my_bitmap*)src; mod->server_set_opcode(mod, opcode); mod->server_paint_rect(mod, x, y, cx, cy, bitmap->data, bitmap->width, bitmap->height, srcx, srcy); mod->server_set_opcode(mod, 0xcc); } /******************************************************************************/ static void DEFAULT_CC ui_triblt(rdpInst* inst, uint8 opcode, int x, int y, int cx, int cy, RD_HBITMAP src, int srcx, int srcy, RD_BRUSH* brush, uint32 bgcolor, uint32 fgcolor) { g_writeln("ui_triblt:"); } /******************************************************************************/ static RD_HGLYPH DEFAULT_CC ui_create_glyph(rdpInst* inst, int width, int height, uint8* data) { g_writeln("ui_create_glyph:"); return 0; } /******************************************************************************/ static void DEFAULT_CC ui_destroy_glyph(rdpInst* inst, RD_HGLYPH glyph) { g_writeln("ui_destroy_glyph:"); } /******************************************************************************/ static int DEFAULT_CC ui_select(rdpInst* inst, int rdp_socket) { return 1; } /******************************************************************************/ static void DEFAULT_CC ui_set_clip(rdpInst* inst, int x, int y, int cx, int cy) { struct mod* mod; mod = GET_MOD(inst); mod->server_set_clip(mod, x, y, cx, cy); } /******************************************************************************/ static void DEFAULT_CC ui_reset_clip(rdpInst* inst) { struct mod* mod; mod = GET_MOD(inst); mod->server_reset_clip(mod); } /******************************************************************************/ static void DEFAULT_CC ui_resize_window(rdpInst* inst) { g_writeln("ui_resize_window:"); } /******************************************************************************/ static void DEFAULT_CC ui_set_cursor(rdpInst* inst, RD_HCURSOR cursor) { struct mod* mod; struct my_cursor* cur; //g_writeln("ui_set_cursor:"); mod = GET_MOD(inst); cur = (struct my_cursor*)cursor; if (cur != 0) { mod->server_set_cursor(mod, cur->hotx, cur->hoty, cur->xormask, cur->andmask); } else { g_writeln("ui_set_cursor: nil cursor"); } } /******************************************************************************/ static void DEFAULT_CC ui_destroy_cursor(rdpInst* inst, RD_HCURSOR cursor) { struct my_cursor* cur; //g_writeln("ui_destroy_cursor:"); cur = (struct my_cursor*)cursor; if (cur != 0) { g_free(cur->andmask); g_free(cur->xormask); } g_free(cur); } #define RGB24(_r, _g, _b) \ (_r << 16) | (_g << 8) | _b; /******************************************************************************/ static int l_get_pixel(tui8* data, int x, int y, int width, int height, int bpp) { int start; int shift; tui16* src16; tui32* src32; int red, green, blue; switch (bpp) { case 1: width = (width + 7) / 8; start = (y * width) + x / 8; shift = x % 8; return (data[start] & (0x80 >> shift)) != 0; case 8: return data[y * width + x]; case 15: case 16: src16 = (uint16*) data; return src16[y * width + x]; case 24: data += y * width * 3; data += x * 3; red = data[0]; green = data[1]; blue = data[2]; return RGB24(red, green, blue); case 32: src32 = (uint32*) data; return src32[y * width + x]; default: g_writeln("l_get_pixel: unknown bpp %d", bpp); break; } return 0; } /******************************************************************************/ static void l_set_pixel(tui8* data, int x, int y, int width, int height, int bpp, int pixel) { int start; int shift; int* dst32; tui8* dst8; if (bpp == 1) { width = (width + 7) / 8; start = (y * width) + x / 8; shift = x % 8; if (pixel) data[start] = data[start] | (0x80 >> shift); else data[start] = data[start] & ~(0x80 >> shift); } else if (bpp == 24) { dst8 = data + (y * width + x) * 3; *(dst8++) = (pixel >> 16) & 0xff; *(dst8++) = (pixel >> 8) & 0xff; *(dst8++) = (pixel >> 0) & 0xff; } else if (bpp == 32) { dst32 = (int*) data; dst32[y * width + x] = pixel; } else { g_writeln("l_set_pixel: unknown bpp %d", bpp); } } /******************************************************************************/ /* andmask = mask = 32 * 32 / 8 xormask = data = 32 * 32 * 3 */ static RD_HCURSOR DEFAULT_CC ui_create_cursor(rdpInst* inst, unsigned int x, unsigned int y, int width, int height, uint8* andmask, uint8* xormask, int bpp) { struct mod* mod; struct my_cursor* cur; int i; int j; int jj; int apixel; int xpixel; char* dst; mod = GET_MOD(inst); g_writeln("ui_create_cursor: x %d y %d width %d height %d bpp %d", x, y, width, height, bpp); cur = (struct my_cursor*)g_malloc(sizeof(struct my_cursor), 1); cur->width = width; cur->height = height; cur->hotx = x; cur->hoty = y; cur->andmask = g_malloc(32 * 32 * 4, 1); cur->xormask = g_malloc(32 * 32 * 4, 1); for (j = 0; j < height; j++) { jj = (bpp != 1) ? j : (height - 1) - j; for (i = 0; i < width; i++) { apixel = l_get_pixel(andmask, i, jj, width, height, 1); xpixel = l_get_pixel(xormask, i, jj, width, height, bpp); xpixel = convert_color(bpp, 24, xpixel, mod->cmap); l_set_pixel(cur->andmask, i, j, width, height, 1, apixel); l_set_pixel(cur->xormask, i, j, width, height, 24, xpixel); } } return (RD_HCURSOR)cur; } /******************************************************************************/ static void DEFAULT_CC ui_set_null_cursor(rdpInst* inst) { g_writeln("ui_set_null_cursor:"); } /******************************************************************************/ static void DEFAULT_CC ui_set_default_cursor(rdpInst* inst) { g_writeln("ui_set_default_cursor:"); } /******************************************************************************/ static RD_HPALETTE DEFAULT_CC ui_create_palette(rdpInst* inst, RD_PALETTE* colors) { struct mod* mod; int index; int red; int green; int blue; int pixel; int count; int* cmap; mod = GET_MOD(inst); g_writeln("ui_create_palette:"); count = 256; if (count > colors->count) { count = colors->count; } cmap = (int*)g_malloc(256 * 4, 1); for (index = 0; index < count; index++) { red = colors->entries[index].red; green = colors->entries[index].green; blue = colors->entries[index].blue; pixel = COLOR24RGB(red, green, blue); cmap[index] = pixel; } return (RD_HPALETTE)cmap; } /******************************************************************************/ static void DEFAULT_CC ui_move_pointer(rdpInst* inst, int x, int y) { g_writeln("ui_move_pointer:"); } /******************************************************************************/ static void DEFAULT_CC ui_set_palette(rdpInst* inst, RD_HPALETTE map) { struct mod* mod; mod = GET_MOD(inst); g_writeln("ui_set_palette:"); g_memcpy(mod->cmap, map, 256 * 4); g_free(map); } /******************************************************************************/ static RD_HBITMAP DEFAULT_CC ui_create_surface(rdpInst* inst, int width, int height, RD_HBITMAP old) { g_writeln("ui_create_surface:"); return 0; } /******************************************************************************/ static void DEFAULT_CC ui_set_surface(rdpInst* inst, RD_HBITMAP surface) { g_writeln("ui_set_surface:"); } /******************************************************************************/ static void DEFAULT_CC ui_destroy_surface(rdpInst* inst, RD_HBITMAP surface) { g_writeln("ui_destroy_surface:"); } /******************************************************************************/ static void DEFAULT_CC ui_channel_data(rdpInst* inst, int chan_id, char* data, int data_size, int flags, int total_size) { g_writeln("ui_channel_data:"); } /******************************************************************************/ static RD_BOOL DEFAULT_CC ui_authenticate(rdpInst * inst) { return 1; } /******************************************************************************/ static int DEFAULT_CC ui_decode(rdpInst * inst, uint8 * data, int data_size) { return 0; } /******************************************************************************/ static RD_BOOL DEFAULT_CC ui_check_certificate(rdpInst * inst, const char * fingerprint, const char * subject, const char * issuer, RD_BOOL verified) { return 1; } /******************************************************************************/ struct mod* EXPORT_CC mod_init(void) { struct mod* mod; //g_writeln("1"); //freerdp_global_init(); //g_writeln("2"); mod = (struct mod*)g_malloc(sizeof(struct mod), 1); mod->size = sizeof(struct mod); mod->version = CURRENT_MOD_VER; mod->handle = (tbus)mod; mod->mod_connect = lib_mod_connect; mod->mod_start = lib_mod_start; mod->mod_event = lib_mod_event; mod->mod_signal = lib_mod_signal; mod->mod_end = lib_mod_end; mod->mod_set_param = lib_mod_set_param; mod->mod_session_change = mod_session_change; mod->mod_get_wait_objs = mod_get_wait_objs; mod->mod_check_wait_objs = mod_check_wait_objs; mod->settings = (struct rdp_set*)g_malloc(sizeof(struct rdp_set), 1); mod->settings->width = 1280; mod->settings->height = 1024; mod->settings->encryption = 1; mod->settings->rdp_security = 1; mod->settings->tls_security = 1; mod->settings->server_depth = 16; mod->settings->bitmap_cache = 1; mod->settings->bitmap_compression = 1; mod->settings->performanceflags = PERF_DISABLE_WALLPAPER | PERF_DISABLE_FULLWINDOWDRAG | PERF_DISABLE_MENUANIMATIONS; mod->settings->new_cursors = 1; mod->settings->rdp_version = 5; mod->settings->text_flags = 1; mod->inst = freerdp_new(mod->settings); if (mod->inst == 0) { return 0; } SET_MOD(mod->inst, mod); mod->inst->ui_error = ui_error; mod->inst->ui_warning = ui_warning; mod->inst->ui_unimpl = ui_unimpl; mod->inst->ui_begin_update = ui_begin_update; mod->inst->ui_end_update = ui_end_update; mod->inst->ui_desktop_save = ui_desktop_save; mod->inst->ui_desktop_restore = ui_desktop_restore; mod->inst->ui_create_bitmap = ui_create_bitmap; mod->inst->ui_paint_bitmap = ui_paint_bitmap; mod->inst->ui_destroy_bitmap = ui_destroy_bitmap; mod->inst->ui_line = ui_line; mod->inst->ui_rect = ui_rect; mod->inst->ui_polygon = ui_polygon; mod->inst->ui_polyline = ui_polyline; mod->inst->ui_ellipse = ui_ellipse; mod->inst->ui_add_char = ui_add_char; mod->inst->ui_draw_text = ui_draw_text; mod->inst->ui_start_draw_glyphs = ui_start_draw_glyphs; mod->inst->ui_draw_glyph = ui_draw_glyph; mod->inst->ui_end_draw_glyphs = ui_end_draw_glyphs; mod->inst->ui_get_toggle_keys_state = ui_get_toggle_keys_state; mod->inst->ui_bell = ui_bell; mod->inst->ui_destblt = ui_destblt; mod->inst->ui_patblt = ui_patblt; mod->inst->ui_screenblt = ui_screenblt; mod->inst->ui_memblt = ui_memblt; mod->inst->ui_triblt = ui_triblt; mod->inst->ui_create_glyph = ui_create_glyph; mod->inst->ui_destroy_glyph = ui_destroy_glyph; mod->inst->ui_select = ui_select; mod->inst->ui_set_clip = ui_set_clip; mod->inst->ui_reset_clip = ui_reset_clip; mod->inst->ui_resize_window = ui_resize_window; mod->inst->ui_set_cursor = ui_set_cursor; mod->inst->ui_destroy_cursor = ui_destroy_cursor; mod->inst->ui_create_cursor = ui_create_cursor; mod->inst->ui_set_null_cursor = ui_set_null_cursor; mod->inst->ui_set_default_cursor = ui_set_default_cursor; mod->inst->ui_create_palette = ui_create_palette; mod->inst->ui_move_pointer = ui_move_pointer; mod->inst->ui_set_palette = ui_set_palette; mod->inst->ui_create_surface = ui_create_surface; mod->inst->ui_set_surface = ui_set_surface; mod->inst->ui_destroy_surface = ui_destroy_surface; mod->inst->ui_channel_data = ui_channel_data; mod->inst->ui_authenticate = ui_authenticate; mod->inst->ui_decode = ui_decode; mod->inst->ui_check_certificate = ui_check_certificate; return mod; } /******************************************************************************/ int EXPORT_CC mod_exit(struct mod* mod) { if (mod == 0) { return 0; } freerdp_free(mod->inst); g_free(mod->settings); g_free(mod); //freerdp_global_finish(); return 0; } xrdp-0.6.0/freerdp/xrdp-freerdp.h000066400000000000000000000106711203155130500166740ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2010 freerdp wrapper */ /* include other h files */ #include "arch.h" #include "parse.h" #include "os_calls.h" #include "defines.h" /* this is the freerdp main header */ #include #define CURRENT_MOD_VER 2 struct mod { int size; /* size of this struct */ int version; /* internal version */ /* client functions */ int (*mod_start)(struct mod* v, int w, int h, int bpp); int (*mod_connect)(struct mod* v); int (*mod_event)(struct mod* v, int msg, long param1, long param2, long param3, long param4); int (*mod_signal)(struct mod* v); int (*mod_end)(struct mod* v); int (*mod_set_param)(struct mod* v, char* name, char* value); int (*mod_session_change)(struct mod* v, int, int); int (*mod_get_wait_objs)(struct mod* v, tbus* read_objs, int* rcount, tbus* write_objs, int* wcount, int* timeout); int (*mod_check_wait_objs)(struct mod* v); long mod_dumby[100 - 9]; /* align, 100 minus the number of mod functions above */ /* server functions */ int (*server_begin_update)(struct mod* v); int (*server_end_update)(struct mod* v); int (*server_fill_rect)(struct mod* v, int x, int y, int cx, int cy); int (*server_screen_blt)(struct mod* v, int x, int y, int cx, int cy, int srcx, int srcy); int (*server_paint_rect)(struct mod* v, int x, int y, int cx, int cy, char* data, int width, int height, int srcx, int srcy); int (*server_set_cursor)(struct mod* v, int x, int y, char* data, char* mask); int (*server_palette)(struct mod* v, int* palette); int (*server_msg)(struct mod* v, char* msg, int code); int (*server_is_term)(struct mod* v); int (*server_set_clip)(struct mod* v, int x, int y, int cx, int cy); int (*server_reset_clip)(struct mod* v); int (*server_set_fgcolor)(struct mod* v, int fgcolor); int (*server_set_bgcolor)(struct mod* v, int bgcolor); int (*server_set_opcode)(struct mod* v, int opcode); int (*server_set_mixmode)(struct mod* v, int mixmode); int (*server_set_brush)(struct mod* v, int x_orgin, int y_orgin, int style, char* pattern); int (*server_set_pen)(struct mod* v, int style, int width); int (*server_draw_line)(struct mod* v, int x1, int y1, int x2, int y2); int (*server_add_char)(struct mod* v, int font, int charactor, int offset, int baseline, int width, int height, char* data); int (*server_draw_text)(struct mod* v, int font, int flags, int mixmode, int clip_left, int clip_top, int clip_right, int clip_bottom, int box_left, int box_top, int box_right, int box_bottom, int x, int y, char* data, int data_len); int (*server_reset)(struct mod* v, int width, int height, int bpp); int (*server_query_channel)(struct mod* v, int index, char* channel_name, int* channel_flags); int (*server_get_channel_id)(struct mod* v, char* name); int (*server_send_to_channel)(struct mod* v, int channel_id, char* data, int data_len, int total_data_len, int flags); int (*server_bell_trigger)(struct mod* v); long server_dumby[100 - 25]; /* align, 100 minus the number of server functions above */ /* common */ tbus handle; /* pointer to self as long */ tbus wm; tbus painter; int sck; /* mod data */ int width; int height; int bpp; struct rdp_set* settings; struct rdp_inst* inst; int cmap[256]; }; xrdp-0.6.0/freerdp1/000077500000000000000000000000001203155130500141755ustar00rootroot00000000000000xrdp-0.6.0/freerdp1/Makefile.am000066400000000000000000000007071203155130500162350ustar00rootroot00000000000000EXTRA_DIST = xrdp-freerdp.h AM_CFLAGS = \ -DXRDP_CFG_PATH=\"${sysconfdir}/xrdp\" \ -DXRDP_SBIN_PATH=\"${sbindir}\" \ -DXRDP_SHARE_PATH=\"${datadir}/xrdp\" \ -DXRDP_PID_PATH=\"${localstatedir}/run\" INCLUDES = \ -I$(top_srcdir)/common \ $(FREERDP_CFLAGS) lib_LTLIBRARIES = \ libxrdpfreerdp1.la libxrdpfreerdp1_la_SOURCES = xrdp-freerdp.c xrdp-color.c libxrdpfreerdp1_la_LIBADD = \ $(top_srcdir)/common/libcommon.la \ $(FREERDP_LIBS) xrdp-0.6.0/freerdp1/xrdp-color.c000066400000000000000000000140531203155130500164350ustar00rootroot00000000000000/** * FreeRDP: A Remote Desktop Protocol Server * freerdp wrapper * * Copyright 2011-2012 Jay Sorg * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "xrdp-freerdp.h" char* APP_CC convert_bitmap(int in_bpp, int out_bpp, char* bmpdata, int width, int height, int* palette) { char* out; char* src; char* dst; int i; int j; int red; int green; int blue; int pixel; if ((in_bpp == 8) && (out_bpp == 8)) { out = (char*)g_malloc(width * height, 0); src = bmpdata; dst = out; for (i = 0; i < height; i++) { for (j = 0; j < width; j++) { pixel = *((tui8*)src); pixel = palette[pixel]; SPLITCOLOR32(red, green, blue, pixel); pixel = COLOR8(red, green, blue); *dst = pixel; src++; dst++; } } return out; } if ((in_bpp == 8) && (out_bpp == 16)) { out = (char*)g_malloc(width * height * 2, 0); src = bmpdata; dst = out; for (i = 0; i < height; i++) { for (j = 0; j < width; j++) { pixel = *((tui8*)src); pixel = palette[pixel]; SPLITCOLOR32(red, green, blue, pixel); pixel = COLOR16(red, green, blue); *((tui16*)dst) = pixel; src++; dst += 2; } } return out; } if ((in_bpp == 8) && (out_bpp == 24)) { out = (char*)g_malloc(width * height * 4, 0); src = bmpdata; dst = out; for (i = 0; i < height; i++) { for (j = 0; j < width; j++) { pixel = *((tui8*)src); pixel = palette[pixel]; SPLITCOLOR32(red, green, blue, pixel); pixel = COLOR24RGB(red, green, blue); *((tui32*)dst) = pixel; src++; dst += 4; } } return out; } if ((in_bpp == 15) && (out_bpp == 16)) { out = (char*)g_malloc(width * height * 2, 0); src = bmpdata; dst = out; for (i = 0; i < height; i++) { for (j = 0; j < width; j++) { pixel = *((tui16*)src); SPLITCOLOR15(red, green, blue, pixel); pixel = COLOR16(red, green, blue); *((tui16*)dst) = pixel; src += 2; dst += 2; } } return out; } if ((in_bpp == 15) && (out_bpp == 24)) { out = (char*)g_malloc(width * height * 4, 0); src = bmpdata; dst = out; for (i = 0; i < height; i++) { for (j = 0; j < width; j++) { pixel = *((tui16*)src); SPLITCOLOR15(red, green, blue, pixel); pixel = COLOR24RGB(red, green, blue); *((tui32*)dst) = pixel; src += 2; dst += 4; } } return out; } if ((in_bpp == 16) && (out_bpp == 16)) { return bmpdata; } if ((in_bpp == 16) && (out_bpp == 24)) { out = (char*)g_malloc(width * height * 4, 0); src = bmpdata; dst = out; for (i = 0; i < height; i++) { for (j = 0; j < width; j++) { pixel = *((tui16*)src); SPLITCOLOR16(red, green, blue, pixel); pixel = COLOR24RGB(red, green, blue); *((tui32*)dst) = pixel; src += 2; dst += 4; } } return out; } if ((in_bpp == 24) && (out_bpp == 24)) { out = (char*)g_malloc(width * height * 4, 0); src = bmpdata; dst = out; for (i = 0; i < height; i++) { for (j = 0; j < width; j++) { blue = *((tui8*)src); src++; green = *((tui8*)src); src++; red = *((tui8*)src); src++; pixel = COLOR24RGB(red, green, blue); *((tui32*)dst) = pixel; dst += 4; } } return out; } if ((in_bpp == 32) && (out_bpp == 24)) { return bmpdata; } if ((in_bpp == 32) && (out_bpp == 32)) { return bmpdata; } g_writeln("convert_bitmap: error unknown conversion from %d to %d", in_bpp, out_bpp); return 0; } /*****************************************************************************/ /* returns color or 0 */ int APP_CC convert_color(int in_bpp, int out_bpp, int in_color, int* palette) { int pixel; int red; int green; int blue; if ((in_bpp == 1) && (out_bpp == 24)) { pixel = in_color == 0 ? 0 : 0xffffff; return pixel; } if ((in_bpp == 8) && (out_bpp == 8)) { pixel = palette[in_color]; SPLITCOLOR32(red, green, blue, pixel); pixel = COLOR8(red, green, blue); return pixel; } if ((in_bpp == 8) && (out_bpp == 16)) { pixel = palette[in_color]; SPLITCOLOR32(red, green, blue, pixel); pixel = COLOR16(red, green, blue); return pixel; } if ((in_bpp == 8) && (out_bpp == 24)) { pixel = palette[in_color]; SPLITCOLOR32(red, green, blue, pixel); pixel = COLOR24BGR(red, green, blue); return pixel; } if ((in_bpp == 15) && (out_bpp == 16)) { pixel = in_color; SPLITCOLOR15(red, green, blue, pixel); pixel = COLOR16(red, green, blue); return pixel; } if ((in_bpp == 15) && (out_bpp == 24)) { pixel = in_color; SPLITCOLOR15(red, green, blue, pixel); pixel = COLOR24BGR(red, green, blue); return pixel; } if ((in_bpp == 16) && (out_bpp == 16)) { return in_color; } if ((in_bpp == 16) && (out_bpp == 24)) { pixel = in_color; SPLITCOLOR16(red, green, blue, pixel); pixel = COLOR24BGR(red, green, blue); return pixel; } if ((in_bpp == 24) && (out_bpp == 24)) { return in_color; } if ((in_bpp == 32) && (out_bpp == 24)) { return in_color; } if ((in_bpp == 32) && (out_bpp == 32)) { return in_color; } g_writeln("convert_color: error unknown conversion from %d to %d", in_bpp, out_bpp); return 0; } xrdp-0.6.0/freerdp1/xrdp-color.h000066400000000000000000000016311203155130500164400ustar00rootroot00000000000000/** * FreeRDP: A Remote Desktop Protocol Server * freerdp wrapper * * Copyright 2011-2012 Jay Sorg * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef __XRDP_COLOR_H #define __XRDP_COLOR_H char* APP_CC convert_bitmap(int in_bpp, int out_bpp, char* bmpdata, int width, int height, int* palette); int APP_CC convert_color(int in_bpp, int out_bpp, int in_color, int* palette); #endif xrdp-0.6.0/freerdp1/xrdp-freerdp.c000066400000000000000000001063401203155130500167470ustar00rootroot00000000000000/** * FreeRDP: A Remote Desktop Protocol Server * freerdp wrapper * * Copyright 2011-2012 Jay Sorg * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "xrdp-freerdp.h" #include "xrdp-color.h" #define LOG_LEVEL 1 #define LLOG(_level, _args) \ do { if (_level < LOG_LEVEL) { g_write _args ; } } while (0) #define LLOGLN(_level, _args) \ do { if (_level < LOG_LEVEL) { g_writeln _args ; } } while (0) struct mod_context { rdpContext _p; struct mod* modi; }; typedef struct mod_context modContext; /*****************************************************************************/ /* return error */ static int DEFAULT_CC lxrdp_start(struct mod* mod, int w, int h, int bpp) { rdpSettings* settings; LLOGLN(10, ("lxrdp_start: w %d h %d bpp %d", w, h, bpp)); settings = mod->inst->settings; settings->width = w; settings->height = h; settings->color_depth = bpp; mod->bpp = bpp; settings->encryption = 1; settings->tls_security = 1; settings->nla_security = 0; settings->rdp_security = 1; return 0; } /******************************************************************************/ /* return error */ static int DEFAULT_CC lxrdp_connect(struct mod* mod) { boolean ok; LLOGLN(10, ("lxrdp_connect:")); ok = freerdp_connect(mod->inst); LLOGLN(0, ("lxrdp_connect: freerdp_connect returned %d", ok)); if (!ok) { return 1; } return 0; } /******************************************************************************/ /* return error */ static int DEFAULT_CC lxrdp_event(struct mod* mod, int msg, long param1, long param2, long param3, long param4) { int x; int y; int flags; int size; int total_size; int chanid; int lchid; char* data; LLOGLN(10, ("lxrdp_event: msg %d", msg)); switch (msg) { case 15: /* key down */ mod->inst->input->KeyboardEvent(mod->inst->input, param4, param3); break; case 16: /* key up */ mod->inst->input->KeyboardEvent(mod->inst->input, param4, param3); break; case 100: /* mouse move */ LLOGLN(10, ("mouse move %d %d", param1, param2)); x = param1; y = param2; flags = PTR_FLAGS_MOVE; mod->inst->input->MouseEvent(mod->inst->input, flags, x, y); break; case 101: /* left button up */ LLOGLN(10, ("left button up %d %d", param1, param2)); x = param1; y = param2; flags = PTR_FLAGS_BUTTON1; mod->inst->input->MouseEvent(mod->inst->input, flags, x, y); break; case 102: /* left button down */ LLOGLN(10, ("left button down %d %d", param1, param2)); x = param1; y = param2; flags = PTR_FLAGS_BUTTON1 | PTR_FLAGS_DOWN; mod->inst->input->MouseEvent(mod->inst->input, flags, x, y); break; case 103: /* right button up */ LLOGLN(10, ("right button up %d %d", param1, param2)); x = param1; y = param2; flags = PTR_FLAGS_BUTTON2; mod->inst->input->MouseEvent(mod->inst->input, flags, x, y); break; case 104: /* right button down */ LLOGLN(10, ("right button down %d %d", param1, param2)); x = param1; y = param2; flags = PTR_FLAGS_BUTTON2 | PTR_FLAGS_DOWN; mod->inst->input->MouseEvent(mod->inst->input, flags, x, y); break; case 105: /* middle button up */ LLOGLN(10, ("middle button up %d %d", param1, param2)); x = param1; y = param2; flags = PTR_FLAGS_BUTTON3; mod->inst->input->MouseEvent(mod->inst->input, flags, x, y); break; case 106: /* middle button down */ LLOGLN(10, ("middle button down %d %d", param1, param2)); x = param1; y = param2; flags = PTR_FLAGS_BUTTON3 | PTR_FLAGS_DOWN; mod->inst->input->MouseEvent(mod->inst->input, flags, x, y); break; case 107: /* wheel up */ flags = PTR_FLAGS_WHEEL | 0x0078; mod->inst->input->MouseEvent(mod->inst->input, flags, 0, 0); case 108: break; case 109: /* wheel down */ flags = PTR_FLAGS_WHEEL | PTR_FLAGS_WHEEL_NEGATIVE | 0x0088; mod->inst->input->MouseEvent(mod->inst->input, flags, 0, 0); case 110: break; case 0x5555: chanid = LOWORD(param1); flags = HIWORD(param1); size = (int)param2; data = (char*)param3; total_size = (int)param4; LLOGLN(10, ("lxrdp_event: client to server flags %d", flags)); if ((chanid < 0) || (chanid >= mod->inst->settings->num_channels)) { LLOGLN(0, ("lxrdp_event: error chanid %d", chanid)); break; } lchid = mod->inst->settings->channels[chanid].channel_id; switch (flags & 3) { case 3: mod->inst->SendChannelData(mod->inst, lchid, data, total_size); break; case 2: /* end */ g_memcpy(mod->chan_buf + mod->chan_buf_valid, data, size); mod->chan_buf_valid += size; mod->inst->SendChannelData(mod->inst, lchid, mod->chan_buf, total_size); g_free(mod->chan_buf); mod->chan_buf = 0; mod->chan_buf_bytes = 0; mod->chan_buf_valid = 0; break; case 1: /* start */ g_free(mod->chan_buf); mod->chan_buf = (char*)g_malloc(total_size, 0); mod->chan_buf_bytes = total_size; mod->chan_buf_valid = 0; g_memcpy(mod->chan_buf + mod->chan_buf_valid, data, size); mod->chan_buf_valid += size; break; default: /* middle */ g_memcpy(mod->chan_buf + mod->chan_buf_valid, data, size); mod->chan_buf_valid += size; break; } break; } return 0; } /******************************************************************************/ /* return error */ static int DEFAULT_CC lxrdp_signal(struct mod* mod) { LLOGLN(10, ("lxrdp_signal:")); return 0; } /******************************************************************************/ /* return error */ static int DEFAULT_CC lxrdp_end(struct mod* mod) { int i; int j; for (j = 0; j < 4; j++) { for (i = 0; i < 4096; i++) { g_free(mod->bitmap_cache[j][i].data); } } for (i = 0; i < 64; i++) { if (mod->brush_cache[i].data != mod->brush_cache[i].b8x8) { g_free(mod->brush_cache[i].data); } } LLOGLN(10, ("lxrdp_end:")); return 0; } /******************************************************************************/ /* return error */ static int DEFAULT_CC lxrdp_set_param(struct mod* mod, char* name, char* value) { rdpSettings* settings; LLOGLN(10, ("lxrdp_set_param: name [%s] value [%s]", name, value)); settings = mod->inst->settings; LLOGLN(10, ("%p %d", settings->hostname, settings->encryption)); if (g_strcmp(name, "hostname") == 0) { } else if (g_strcmp(name, "ip") == 0) { settings->hostname = g_strdup(value); } else if (g_strcmp(name, "port") == 0) { settings->port = g_atoi(value); } else if (g_strcmp(name, "keylayout") == 0) { } else if (g_strcmp(name, "name") == 0) { } else if (g_strcmp(name, "lib") == 0) { } else { LLOGLN(0, ("lxrdp_set_param: unknown name [%s] value [%s]", name, value)); } return 0; } /******************************************************************************/ static int DEFAULT_CC lxrdp_session_change(struct mod* mod, int a, int b) { LLOGLN(10, ("lxrdp_session_change:")); return 0; } /******************************************************************************/ static int DEFAULT_CC lxrdp_get_wait_objs(struct mod* mod, tbus* read_objs, int* rcount, tbus* write_objs, int* wcount, int* timeout) { void** rfds; void** wfds; boolean ok; LLOGLN(10, ("lxrdp_get_wait_objs:")); rfds = (void**)read_objs; wfds = (void**)write_objs; ok = freerdp_get_fds(mod->inst, rfds, rcount, wfds, wcount); if (!ok) { LLOGLN(0, ("lxrdp_get_wait_objs: freerdp_get_fds failed")); return 1; } return 0; } /******************************************************************************/ static int DEFAULT_CC lxrdp_check_wait_objs(struct mod* mod) { boolean ok; LLOGLN(10, ("lxrdp_check_wait_objs:")); ok = freerdp_check_fds(mod->inst); if (!ok) { LLOGLN(0, ("lxrdp_check_wait_objs: freerdp_check_fds failed")); return 1; } return 0; } /******************************************************************************/ static void DEFAULT_CC lfreerdp_begin_paint(rdpContext* context) { struct mod* mod; LLOGLN(10, ("lfreerdp_begin_paint:")); mod = ((struct mod_context*)context)->modi; mod->server_begin_update(mod); } /******************************************************************************/ static void DEFAULT_CC lfreerdp_end_paint(rdpContext* context) { struct mod* mod; LLOGLN(10, ("lfreerdp_end_paint:")); mod = ((struct mod_context*)context)->modi; mod->server_end_update(mod); } /******************************************************************************/ static void DEFAULT_CC lfreerdp_set_bounds(rdpContext* context, rdpBounds* bounds) { struct mod* mod; int x; int y; int cx; int cy; LLOGLN(10, ("lfreerdp_set_bounds: %p", bounds)); mod = ((struct mod_context*)context)->modi; if (bounds != 0) { x = bounds->left; y = bounds->top; cx = (bounds->right - bounds->left) + 1; cy = (bounds->bottom - bounds->top) + 1; mod->server_set_clip(mod, x, y, cx, cy); } else { mod->server_reset_clip(mod); } } /******************************************************************************/ static void DEFAULT_CC lfreerdp_bitmap_update(rdpContext* context, BITMAP_UPDATE* bitmap) { struct mod* mod; int index; int cx; int cy; int server_bpp; int server_Bpp; int client_bpp; int j; int line_bytes; BITMAP_DATA* bd; tui8* dst_data; tui8* dst_data1; tui8* src; tui8* dst; mod = ((struct mod_context*)context)->modi; LLOGLN(10, ("lfreerdp_bitmap_update: %d %d", bitmap->number, bitmap->count)); server_bpp = mod->inst->settings->color_depth; server_Bpp = (server_bpp + 7) / 8; client_bpp = mod->bpp; for (index = 0; index < bitmap->number; index++) { bd = bitmap->rectangles + index; cx = (bd->destRight - bd->destLeft) + 1; cy = (bd->destBottom - bd->destTop) + 1; line_bytes = server_Bpp * bd->width; dst_data = (tui8*)g_malloc(bd->height * line_bytes + 16, 0); if (bd->compressed) { bitmap_decompress(bd->bitmapDataStream, dst_data, bd->width, bd->height, bd->bitmapLength, server_bpp, server_bpp); } else { /* bitmap is upside down */ src = bd->bitmapDataStream; dst = dst_data + bd->height * line_bytes; for (j = 0; j < bd->height; j++) { dst -= line_bytes; g_memcpy(dst, src, line_bytes); src += line_bytes; } } dst_data1 = convert_bitmap(server_bpp, client_bpp, dst_data, bd->width, bd->height, mod->colormap); mod->server_paint_rect(mod, bd->destLeft, bd->destTop, cx, cy, dst_data1, bd->width, bd->height, 0, 0); if (dst_data1 != dst_data) { g_free(dst_data1); } g_free(dst_data); } } /******************************************************************************/ static void DEFAULT_CC lfreerdp_dst_blt(rdpContext* context, DSTBLT_ORDER* dstblt) { struct mod* mod; mod = ((struct mod_context*)context)->modi; LLOGLN(10, ("lfreerdp_dst_blt:")); mod->server_set_opcode(mod, dstblt->bRop); mod->server_fill_rect(mod, dstblt->nLeftRect, dstblt->nTopRect, dstblt->nWidth, dstblt->nHeight); mod->server_set_opcode(mod, 0xcc); } /******************************************************************************/ static void DEFAULT_CC lfreerdp_pat_blt(rdpContext* context, PATBLT_ORDER* patblt) { struct mod* mod; int idx; int fgcolor; int bgcolor; int server_bpp; int client_bpp; struct brush_item* bi; mod = ((struct mod_context*)context)->modi; LLOGLN(10, ("lfreerdp_pat_blt:")); server_bpp = mod->inst->settings->color_depth; client_bpp = mod->bpp; LLOGLN(0, ("lfreerdp_pat_blt: bpp %d %d", server_bpp, client_bpp)); fgcolor = convert_color(server_bpp, client_bpp, patblt->foreColor, mod->colormap); bgcolor = convert_color(server_bpp, client_bpp, patblt->backColor, mod->colormap); mod->server_set_mixmode(mod, 1); mod->server_set_opcode(mod, patblt->bRop); mod->server_set_fgcolor(mod, fgcolor); mod->server_set_bgcolor(mod, bgcolor); if (patblt->brush.style & 0x80) { idx = patblt->brush.hatch; if ((idx < 0) || (idx >= 64)) { LLOGLN(0, ("lfreerdp_pat_blt: error")); return; } bi = mod->brush_cache + idx; mod->server_set_brush(mod, patblt->brush.x, patblt->brush.y, 3, bi->b8x8); } else { mod->server_set_brush(mod, patblt->brush.x, patblt->brush.y, patblt->brush.style, patblt->brush.p8x8); } mod->server_fill_rect(mod, patblt->nLeftRect, patblt->nTopRect, patblt->nWidth, patblt->nHeight); mod->server_set_opcode(mod, 0xcc); mod->server_set_mixmode(mod, 0); } /******************************************************************************/ static void DEFAULT_CC lfreerdp_scr_blt(rdpContext* context, SCRBLT_ORDER* scrblt) { struct mod* mod; mod = ((struct mod_context*)context)->modi; LLOGLN(10, ("lfreerdp_scr_blt:")); mod->server_set_opcode(mod, scrblt->bRop); mod->server_screen_blt(mod, scrblt->nLeftRect, scrblt->nTopRect, scrblt->nWidth, scrblt->nHeight, scrblt->nXSrc, scrblt->nYSrc); mod->server_set_opcode(mod, 0xcc); } /******************************************************************************/ static void DEFAULT_CC lfreerdp_opaque_rect(rdpContext* context, OPAQUE_RECT_ORDER* opaque_rect) { struct mod* mod; int server_bpp; int client_bpp; int fgcolor; mod = ((struct mod_context*)context)->modi; LLOGLN(10, ("lfreerdp_opaque_rect:")); server_bpp = mod->inst->settings->color_depth; client_bpp = mod->bpp; fgcolor = convert_color(server_bpp, client_bpp, opaque_rect->color, mod->colormap); mod->server_set_fgcolor(mod, fgcolor); mod->server_fill_rect(mod, opaque_rect->nLeftRect, opaque_rect->nTopRect, opaque_rect->nWidth, opaque_rect->nHeight); } /******************************************************************************/ static void DEFAULT_CC lfreerdp_mem_blt(rdpContext* context, MEMBLT_ORDER* memblt) { int id; int idx; struct mod* mod; struct bitmap_item* bi; mod = ((struct mod_context*)context)->modi; LLOGLN(10, ("lfreerdp_mem_blt: cacheId %d cacheIndex %d", memblt->cacheId, memblt->cacheIndex)); id = memblt->cacheId; idx = memblt->cacheIndex; if (idx == 32767) /* BITMAPCACHE_WAITING_LIST_INDEX */ { idx = 4096 - 1; } if ((id < 0) || (id >= 4)) { LLOGLN(0, ("lfreerdp_mem_blt: bad id [%d]", id)); return; } if ((idx < 0) || (idx >= 4096)) { LLOGLN(0, ("lfreerdp_mem_blt: bad idx [%d]", idx)); return; } bi = &(mod->bitmap_cache[id][idx]); mod->server_set_opcode(mod, memblt->bRop); mod->server_paint_rect(mod, memblt->nLeftRect, memblt->nTopRect, memblt->nWidth, memblt->nHeight, bi->data, bi->width, bi->height, memblt->nXSrc, memblt->nYSrc); mod->server_set_opcode(mod, 0xcc); } /******************************************************************************/ static void DEFAULT_CC lfreerdp_glyph_index(rdpContext* context, GLYPH_INDEX_ORDER* glyph_index) { struct mod* mod; int server_bpp; int client_bpp; int fgcolor; int bgcolor; mod = ((struct mod_context*)context)->modi; LLOGLN(10, ("lfreerdp_glyph_index:")); server_bpp = mod->inst->settings->color_depth; client_bpp = mod->bpp; fgcolor = convert_color(server_bpp, client_bpp, glyph_index->foreColor, mod->colormap); bgcolor = convert_color(server_bpp, client_bpp, glyph_index->backColor, mod->colormap); mod->server_set_bgcolor(mod, fgcolor); mod->server_set_fgcolor(mod, bgcolor); mod->server_draw_text(mod, glyph_index->cacheId, glyph_index->flAccel, glyph_index->fOpRedundant, glyph_index->bkLeft, glyph_index->bkTop, glyph_index->bkRight, glyph_index->bkBottom, glyph_index->opLeft, glyph_index->opTop, glyph_index->opRight, glyph_index->opBottom, glyph_index->x, glyph_index->y, glyph_index->data, glyph_index->cbData); } /******************************************************************************/ static void DEFAULT_CC lfreerdp_line_to(rdpContext* context, LINE_TO_ORDER* line_to) { struct mod* mod; int server_bpp; int client_bpp; int fgcolor; int bgcolor; mod = ((struct mod_context*)context)->modi; LLOGLN(10, ("lfreerdp_line_to:")); mod->server_set_opcode(mod, line_to->bRop2); server_bpp = mod->inst->settings->color_depth; client_bpp = mod->bpp; fgcolor = convert_color(server_bpp, client_bpp, line_to->penColor, mod->colormap); bgcolor = convert_color(server_bpp, client_bpp, line_to->backColor, mod->colormap); mod->server_set_fgcolor(mod, fgcolor); mod->server_set_bgcolor(mod, bgcolor); mod->server_set_pen(mod, line_to->penStyle, line_to->penWidth); mod->server_draw_line(mod, line_to->nXStart, line_to->nYStart, line_to->nXEnd, line_to->nYEnd); mod->server_set_opcode(mod, 0xcc); } /******************************************************************************/ static void DEFAULT_CC lfreerdp_cache_bitmap(rdpContext* context, CACHE_BITMAP_ORDER* cache_bitmap_order) { LLOGLN(10, ("lfreerdp_cache_bitmap:")); } /******************************************************************************/ static void DEFAULT_CC lfreerdp_cache_bitmapV2(rdpContext* context, CACHE_BITMAP_V2_ORDER* cache_bitmap_v2_order) { char* dst_data; char* dst_data1; int bytes; int width; int height; int id; int idx; int flags; int server_bpp; int server_Bpp; int client_bpp; struct mod* mod; LLOGLN(10, ("lfreerdp_cache_bitmapV2: %d %d 0x%8.8x compressed %d", cache_bitmap_v2_order->cacheId, cache_bitmap_v2_order->cacheIndex, cache_bitmap_v2_order->flags, cache_bitmap_v2_order->compressed)); mod = ((struct mod_context*)context)->modi; id = cache_bitmap_v2_order->cacheId; idx = cache_bitmap_v2_order->cacheIndex; flags = cache_bitmap_v2_order->flags; if (flags & 0x10) /* CBR2_DO_NOT_CACHE */ { idx = 4096 - 1; } if ((id < 0) || (id >= 4)) { LLOGLN(0, ("lfreerdp_cache_bitmapV2: bad id [%d]", id)); return; } if ((idx < 0) || (idx >= 4096)) { LLOGLN(0, ("lfreerdp_cache_bitmapV2: bad idx [%d]", idx)); return; } server_bpp = mod->inst->settings->color_depth; server_Bpp = (server_bpp + 7) / 8; client_bpp = mod->bpp; width = cache_bitmap_v2_order->bitmapWidth; height = cache_bitmap_v2_order->bitmapHeight; bytes = width * height * server_Bpp + 16; dst_data = (char*)g_malloc(bytes, 0); if (cache_bitmap_v2_order->compressed) { bitmap_decompress(cache_bitmap_v2_order->bitmapDataStream, dst_data, width, height, cache_bitmap_v2_order->bitmapLength, server_bpp, server_bpp); } else { g_memcpy(dst_data, cache_bitmap_v2_order->bitmapDataStream, width * height * server_Bpp); } dst_data1 = convert_bitmap(server_bpp, client_bpp, dst_data, width, height, mod->colormap); g_free(mod->bitmap_cache[id][idx].data); mod->bitmap_cache[id][idx].width = width; mod->bitmap_cache[id][idx].height = height; mod->bitmap_cache[id][idx].data = dst_data1; if (dst_data != dst_data1) { g_free(dst_data); } } /******************************************************************************/ static void DEFAULT_CC lfreerdp_cache_glyph(rdpContext* context, CACHE_GLYPH_ORDER* cache_glyph_order) { int index; GLYPH_DATA* gd; struct mod* mod; mod = ((struct mod_context*)context)->modi; LLOGLN(10, ("lfreerdp_cache_glyph: %d", cache_glyph_order->cGlyphs)); for (index = 0; index < cache_glyph_order->cGlyphs; index++) { gd = cache_glyph_order->glyphData[index]; LLOGLN(10, (" %d %d %d %d %d", gd->cacheIndex, gd->x, gd->y, gd->cx, gd->cy)); mod->server_add_char(mod, cache_glyph_order->cacheId, gd->cacheIndex, gd->x, gd->y, gd->cx, gd->cy, gd->aj); xfree(gd->aj); gd->aj = 0; xfree(gd); cache_glyph_order->glyphData[index] = 0; } xfree(cache_glyph_order->unicodeCharacters); cache_glyph_order->unicodeCharacters = 0; } /******************************************************************************/ static void DEFAULT_CC lfreerdp_cache_brush(rdpContext* context, CACHE_BRUSH_ORDER* cache_brush_order) { int idx; int bytes; int bpp; int cx; int cy; struct mod* mod; mod = ((struct mod_context*)context)->modi; bpp = cache_brush_order->bpp; cx = cache_brush_order->cx; cy = cache_brush_order->cy; idx = cache_brush_order->index; bytes = cache_brush_order->length; LLOGLN(10, ("lfreerdp_cache_brush: bpp %d cx %d cy %d idx %d bytes %d", bpp, cx, cy, idx, bytes)); if ((idx < 0) || (idx >= 64)) { LLOGLN(0, ("lfreerdp_cache_brush: error idx %d", idx)); return; } if ((bpp != 1) || (cx != 8) || (cy != 8)) { LLOGLN(0, ("lfreerdp_cache_brush: error unsupported brush " "bpp %d cx %d cy %d", bpp, cx, cy)); return; } mod->brush_cache[idx].bpp = bpp; mod->brush_cache[idx].width = cx; mod->brush_cache[idx].height = cy; mod->brush_cache[idx].data = mod->brush_cache[idx].b8x8; if (bytes > 8) { bytes = 8; } g_memset(mod->brush_cache[idx].data, 0, 8); if (bytes > 0) { if (bytes > 8) { LLOGLN(0, ("lfreerdp_cache_brush: bytes to big %d", bytes)); bytes = 8; } g_memcpy(mod->brush_cache[idx].data, cache_brush_order->data, bytes); } LLOGLN(10, ("lfreerdp_cache_brush: out bpp %d cx %d cy %d idx %d bytes %d", bpp, cx, cy, idx, bytes)); xfree(cache_brush_order->data); cache_brush_order->data = 0; } /******************************************************************************/ static void DEFAULT_CC lfreerdp_pointer_position(rdpContext* context, POINTER_POSITION_UPDATE* pointer_position) { LLOGLN(0, ("lfreerdp_pointer_position:")); } /******************************************************************************/ static void DEFAULT_CC lfreerdp_pointer_system(rdpContext* context, POINTER_SYSTEM_UPDATE* pointer_system) { LLOGLN(0, ("lfreerdp_pointer_system:")); } /******************************************************************************/ static void DEFAULT_CC lfreerdp_pointer_color(rdpContext* context, POINTER_COLOR_UPDATE* pointer_color) { LLOGLN(0, ("lfreerdp_pointer_color:")); } /******************************************************************************/ static int APP_CC lfreerdp_get_pixel(void* bits, int width, int height, int bpp, int delta, int x, int y) { int start; int shift; int pixel; tui8* src8; if (bpp == 1) { src8 = (tui8*)bits; start = (y * delta) + x / 8; shift = x % 8; pixel = (src8[start] & (0x80 >> shift)) != 0; return pixel ? 0xffffff : 0; } else { LLOGLN(0, ("lfreerdp_get_pixel: unknown bpp %d", bpp)); } return 0; } /******************************************************************************/ static int APP_CC lfreerdp_set_pixel(int pixel, void* bits, int width, int height, int bpp, int delta, int x, int y) { tui8* dst8; int start; int shift; if (bpp == 1) { dst8 = (tui8*)bits; start = (y * delta) + x / 8; shift = x % 8; if (pixel) { dst8[start] = dst8[start] | (0x80 >> shift); } else { dst8[start] = dst8[start] & ~(0x80 >> shift); } } else if (bpp == 24) { dst8 = (tui8*)bits; dst8 += y * delta + x * 3; dst8[0] = (pixel >> 0) & 0xff; dst8[1] = (pixel >> 8) & 0xff; dst8[2] = (pixel >> 16) & 0xff; } else { LLOGLN(0, ("lfreerdp_set_pixel: unknown bpp %d", bpp)); } return 0; } /******************************************************************************/ static int APP_CC lfreerdp_convert_color_image(void* dst, int dst_width, int dst_height, int dst_bpp, int dst_delta, void* src, int src_width, int src_height, int src_bpp, int src_delta) { int i; int j; int pixel; for (j = 0; j < dst_height; j++) { for (i = 0; i < dst_width; i++) { pixel = lfreerdp_get_pixel(src, src_width, src_height, src_bpp, src_delta, i, j); lfreerdp_set_pixel(pixel, dst, dst_width, dst_height, dst_bpp, dst_delta, i, j); } } return 0; } /******************************************************************************/ static void DEFAULT_CC lfreerdp_pointer_new(rdpContext* context, POINTER_NEW_UPDATE* pointer_new) { struct mod* mod; int index; tui8* dst; tui8* src; mod = ((struct mod_context*)context)->modi; LLOGLN(0, ("lfreerdp_pointer_new:")); LLOGLN(0, (" bpp %d", pointer_new->xorBpp)); LLOGLN(0, (" width %d height %d", pointer_new->colorPtrAttr.width, pointer_new->colorPtrAttr.height)); LLOGLN(0, (" lengthXorMask %d lengthAndMask %d", pointer_new->colorPtrAttr.lengthXorMask, pointer_new->colorPtrAttr.lengthAndMask)); index = pointer_new->colorPtrAttr.cacheIndex; if (pointer_new->xorBpp == 1 && pointer_new->colorPtrAttr.width == 32 && pointer_new->colorPtrAttr.height == 32 && index < 32) { mod->pointer_cache[index].hotx = pointer_new->colorPtrAttr.xPos; mod->pointer_cache[index].hoty = pointer_new->colorPtrAttr.yPos; dst = mod->pointer_cache[index].data; dst += 32 * 32 * 3 - 32 * 3; src = pointer_new->colorPtrAttr.xorMaskData; lfreerdp_convert_color_image(dst, 32, 32, 24, 32 * -3, src, 32, 32, 1, 32 / 8); dst = mod->pointer_cache[index].mask; dst += 32 * 32 / 8 - 32 / 8; src = pointer_new->colorPtrAttr.andMaskData; lfreerdp_convert_color_image(dst, 32, 32, 1, 32 / -8, src, 32, 32, 1, 32 / 8); //memcpy(mod->pointer_cache[index].mask, // pointer_new->colorPtrAttr.andMaskData, 32 * 32 / 8); mod->server_set_cursor(mod, mod->pointer_cache[index].hotx, mod->pointer_cache[index].hoty, mod->pointer_cache[index].data, mod->pointer_cache[index].mask); } else { LLOGLN(0, ("lfreerdp_pointer_new: error")); } xfree(pointer_new->colorPtrAttr.xorMaskData); pointer_new->colorPtrAttr.xorMaskData = 0; xfree(pointer_new->colorPtrAttr.andMaskData); pointer_new->colorPtrAttr.andMaskData = 0; } /******************************************************************************/ static void DEFAULT_CC lfreerdp_pointer_cached(rdpContext* context, POINTER_CACHED_UPDATE* pointer_cached) { struct mod* mod; int index; LLOGLN(0, ("lfreerdp_pointer_cached:")); mod = ((struct mod_context*)context)->modi; index = pointer_cached->cacheIndex; mod->server_set_cursor(mod, mod->pointer_cache[index].hotx, mod->pointer_cache[index].hoty, mod->pointer_cache[index].data, mod->pointer_cache[index].mask); } /******************************************************************************/ static boolean DEFAULT_CC lfreerdp_pre_connect(freerdp* instance) { struct mod* mod; int index; int error; int num_chans; int ch_flags; char ch_name[256]; char* dst_ch_name; LLOGLN(0, ("lfreerdp_pre_connect:")); mod = ((struct mod_context*)(instance->context))->modi; num_chans = 0; index = 0; error = mod->server_query_channel(mod, index, ch_name, &ch_flags); while (error == 0) { num_chans++; LLOGLN(10, ("lfreerdp_pre_connect: got channel [%s], flags [0x%8.8x]", ch_name, ch_flags)); dst_ch_name = instance->settings->channels[index].name; g_memset(dst_ch_name, 0, 8); g_snprintf(dst_ch_name, 8, "%s", ch_name); instance->settings->channels[index].options = ch_flags; index++; error = mod->server_query_channel(mod, index, ch_name, &ch_flags); } instance->settings->num_channels = num_chans; instance->settings->offscreen_bitmap_cache = false; instance->settings->glyph_cache = true; instance->settings->glyphSupportLevel = GLYPH_SUPPORT_FULL; instance->settings->order_support[NEG_GLYPH_INDEX_INDEX] = true; instance->settings->order_support[NEG_FAST_GLYPH_INDEX] = false; instance->settings->order_support[NEG_FAST_INDEX_INDEX] = false; instance->settings->order_support[NEG_SCRBLT_INDEX] = true; instance->settings->order_support[NEG_SAVEBITMAP_INDEX] = false; instance->settings->bitmap_cache = true; instance->settings->order_support[NEG_MEMBLT_INDEX] = true; instance->settings->order_support[NEG_MEMBLT_V2_INDEX] = true; instance->settings->order_support[NEG_MEM3BLT_INDEX] = false; instance->settings->order_support[NEG_MEM3BLT_V2_INDEX] = false; instance->settings->bitmapCacheV2NumCells = 3; // 5; instance->settings->bitmapCacheV2CellInfo[0].numEntries = 0x78; // 600; instance->settings->bitmapCacheV2CellInfo[0].persistent = false; instance->settings->bitmapCacheV2CellInfo[1].numEntries = 0x78; // 600; instance->settings->bitmapCacheV2CellInfo[1].persistent = false; instance->settings->bitmapCacheV2CellInfo[2].numEntries = 0x150; // 2048; instance->settings->bitmapCacheV2CellInfo[2].persistent = false; instance->settings->bitmapCacheV2CellInfo[3].numEntries = 0; // 4096; instance->settings->bitmapCacheV2CellInfo[3].persistent = false; instance->settings->bitmapCacheV2CellInfo[4].numEntries = 0; // 2048; instance->settings->bitmapCacheV2CellInfo[4].persistent = false; instance->settings->order_support[NEG_MULTIDSTBLT_INDEX] = false; instance->settings->order_support[NEG_MULTIPATBLT_INDEX] = false; instance->settings->order_support[NEG_MULTISCRBLT_INDEX] = false; instance->settings->order_support[NEG_MULTIOPAQUERECT_INDEX] = false; instance->settings->order_support[NEG_POLYLINE_INDEX] = false; // here //instance->settings->rdp_version = 4; instance->update->BeginPaint = lfreerdp_begin_paint; instance->update->EndPaint = lfreerdp_end_paint; instance->update->SetBounds = lfreerdp_set_bounds; instance->update->BitmapUpdate = lfreerdp_bitmap_update; instance->update->primary->DstBlt = lfreerdp_dst_blt; instance->update->primary->PatBlt = lfreerdp_pat_blt; instance->update->primary->ScrBlt = lfreerdp_scr_blt; instance->update->primary->OpaqueRect = lfreerdp_opaque_rect; instance->update->primary->MemBlt = lfreerdp_mem_blt; instance->update->primary->GlyphIndex = lfreerdp_glyph_index; instance->update->primary->LineTo = lfreerdp_line_to; instance->update->secondary->CacheBitmap = lfreerdp_cache_bitmap; instance->update->secondary->CacheBitmapV2 = lfreerdp_cache_bitmapV2; instance->update->secondary->CacheGlyph = lfreerdp_cache_glyph; instance->update->secondary->CacheBrush = lfreerdp_cache_brush; instance->update->pointer->PointerPosition = lfreerdp_pointer_position; instance->update->pointer->PointerSystem = lfreerdp_pointer_system; instance->update->pointer->PointerColor = lfreerdp_pointer_color; instance->update->pointer->PointerNew = lfreerdp_pointer_new; instance->update->pointer->PointerCached = lfreerdp_pointer_cached; return true; } /******************************************************************************/ static boolean DEFAULT_CC lfreerdp_post_connect(freerdp* instance) { LLOGLN(0, ("lfreerdp_post_connect:")); return true; } /******************************************************************************/ static void DEFAULT_CC lfreerdp_context_new(freerdp* instance, rdpContext* context) { LLOGLN(0, ("lfreerdp_context_new: %p", context)); } /******************************************************************************/ static void DEFAULT_CC lfreerdp_context_free(freerdp* instance, rdpContext* context) { LLOGLN(0, ("lfreerdp_context_free:")); } /******************************************************************************/ static int DEFAULT_CC lfreerdp_receive_channel_data(freerdp* instance, int channelId, uint8* data, int size, int flags, int total_size) { struct mod* mod; int lchid; int index; int error; mod = ((struct mod_context*)(instance->context))->modi; lchid = -1; for (index = 0; index < instance->settings->num_channels; index++) { if (instance->settings->channels[index].channel_id == channelId) { lchid = index; break; } } if (lchid >= 0) { LLOGLN(10, ("lfreerdp_receive_channel_data: server to client")); error = mod->server_send_to_channel(mod, lchid, data, size, total_size, flags); if (error != 0) { LLOGLN(0, ("lfreerdp_receive_channel_data: error %d", error)); } } else { LLOGLN(0, ("lfreerdp_receive_channel_data: bad lchid")); } return 0; } /******************************************************************************/ struct mod* EXPORT_CC mod_init(void) { struct mod* mod; modContext* lcon; LLOGLN(0, ("mod_init:")); mod = (struct mod*)g_malloc(sizeof(struct mod), 1); freerdp_get_version(&(mod->vmaj), &(mod->vmin), &(mod->vrev)); LLOGLN(0, (" FreeRDP version major %d minor %d revision %d", mod->vmaj, mod->vmin, mod->vrev)); mod->size = sizeof(struct mod); mod->version = CURRENT_MOD_VER; mod->handle = (tbus)mod; mod->mod_connect = lxrdp_connect; mod->mod_start = lxrdp_start; mod->mod_event = lxrdp_event; mod->mod_signal = lxrdp_signal; mod->mod_end = lxrdp_end; mod->mod_set_param = lxrdp_set_param; mod->mod_session_change = lxrdp_session_change; mod->mod_get_wait_objs = lxrdp_get_wait_objs; mod->mod_check_wait_objs = lxrdp_check_wait_objs; mod->inst = freerdp_new(); mod->inst->PreConnect = lfreerdp_pre_connect; mod->inst->PostConnect = lfreerdp_post_connect; mod->inst->context_size = sizeof(modContext); mod->inst->ContextNew = lfreerdp_context_new; mod->inst->ContextFree = lfreerdp_context_free; mod->inst->ReceiveChannelData = lfreerdp_receive_channel_data; freerdp_context_new(mod->inst); lcon = (modContext*)(mod->inst->context); lcon->modi = mod; LLOGLN(10, ("mod_init: mod %p", mod)); return mod; } /******************************************************************************/ int EXPORT_CC mod_exit(struct mod* mod) { LLOGLN(0, ("mod_exit:")); if (mod == 0) { return 0; } if ((mod->vmaj == 1) && (mod->vmin == 0) && (mod->vrev == 1)) { /* this version has a bug with double free in freerdp_free */ } else { freerdp_context_free(mod->inst); } freerdp_free(mod->inst); g_free(mod); return 0; } xrdp-0.6.0/freerdp1/xrdp-freerdp.h000066400000000000000000000115111203155130500167470ustar00rootroot00000000000000/** * FreeRDP: A Remote Desktop Protocol Server * freerdp wrapper * * Copyright 2011-2012 Jay Sorg * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* include other h files */ #include "arch.h" #include "parse.h" #include "os_calls.h" #include "defines.h" /* this is the freerdp main header */ #include //#include "/home/jay/git/jsorg71/staging/include/freerdp/freerdp.h" struct bitmap_item { int width; int height; char* data; }; struct brush_item { int bpp; int width; int height; char* data; char b8x8[8]; }; struct pointer_item { int hotx; int hoty; char data[32 * 32 * 3]; char mask[32 * 32 / 8]; }; #define CURRENT_MOD_VER 2 struct mod { int size; /* size of this struct */ int version; /* internal version */ /* client functions */ int (*mod_start)(struct mod* v, int w, int h, int bpp); int (*mod_connect)(struct mod* v); int (*mod_event)(struct mod* v, int msg, long param1, long param2, long param3, long param4); int (*mod_signal)(struct mod* v); int (*mod_end)(struct mod* v); int (*mod_set_param)(struct mod* v, char* name, char* value); int (*mod_session_change)(struct mod* v, int, int); int (*mod_get_wait_objs)(struct mod* v, tbus* read_objs, int* rcount, tbus* write_objs, int* wcount, int* timeout); int (*mod_check_wait_objs)(struct mod* v); long mod_dumby[100 - 9]; /* align, 100 minus the number of mod functions above */ /* server functions */ int (*server_begin_update)(struct mod* v); int (*server_end_update)(struct mod* v); int (*server_fill_rect)(struct mod* v, int x, int y, int cx, int cy); int (*server_screen_blt)(struct mod* v, int x, int y, int cx, int cy, int srcx, int srcy); int (*server_paint_rect)(struct mod* v, int x, int y, int cx, int cy, char* data, int width, int height, int srcx, int srcy); int (*server_set_cursor)(struct mod* v, int x, int y, char* data, char* mask); int (*server_palette)(struct mod* v, int* palette); int (*server_msg)(struct mod* v, char* msg, int code); int (*server_is_term)(struct mod* v); int (*server_set_clip)(struct mod* v, int x, int y, int cx, int cy); int (*server_reset_clip)(struct mod* v); int (*server_set_fgcolor)(struct mod* v, int fgcolor); int (*server_set_bgcolor)(struct mod* v, int bgcolor); int (*server_set_opcode)(struct mod* v, int opcode); int (*server_set_mixmode)(struct mod* v, int mixmode); int (*server_set_brush)(struct mod* v, int x_orgin, int y_orgin, int style, char* pattern); int (*server_set_pen)(struct mod* v, int style, int width); int (*server_draw_line)(struct mod* v, int x1, int y1, int x2, int y2); int (*server_add_char)(struct mod* v, int font, int charactor, int offset, int baseline, int width, int height, char* data); int (*server_draw_text)(struct mod* v, int font, int flags, int mixmode, int clip_left, int clip_top, int clip_right, int clip_bottom, int box_left, int box_top, int box_right, int box_bottom, int x, int y, char* data, int data_len); int (*server_reset)(struct mod* v, int width, int height, int bpp); int (*server_query_channel)(struct mod* v, int index, char* channel_name, int* channel_flags); int (*server_get_channel_id)(struct mod* v, char* name); int (*server_send_to_channel)(struct mod* v, int channel_id, char* data, int data_len, int total_data_len, int flags); int (*server_bell_trigger)(struct mod* v); long server_dumby[100 - 25]; /* align, 100 minus the number of server functions above */ /* common */ tbus handle; /* pointer to self as long */ tbus wm; tbus painter; int sck; /* mod data */ int width; int height; int bpp; int colormap[256]; char* chan_buf; int chan_buf_valid; int chan_buf_bytes; int vmaj; int vmin; int vrev; struct rdp_freerdp* inst; struct bitmap_item bitmap_cache[4][4096]; struct brush_item brush_cache[64]; struct pointer_item pointer_cache[32]; }; xrdp-0.6.0/genkeymap/000077500000000000000000000000001203155130500144455ustar00rootroot00000000000000xrdp-0.6.0/genkeymap/Makefile.am000066400000000000000000000002001203155130500164710ustar00rootroot00000000000000 bin_PROGRAMS = \ xrdp-genkeymap xrdp_genkeymap_SOURCES = genkeymap.c xrdp_genkeymap_LDADD = \ -L/usr/X11R6/lib \ -lX11 xrdp-0.6.0/genkeymap/dump-keymaps.sh000077500000000000000000000012121203155130500174140ustar00rootroot00000000000000#!/bin/sh which setxkbmap if test $? -ne 0 then echo "error, setxkbmap not found" exit 1 fi # English - US 'en-us' 0x0409 setxkbmap -model pc104 -layout us ./xrdp-genkeymap ../instfiles/km-0409.ini # German 'de' 0x0407 setxkbmap -model pc104 -layout de ./xrdp-genkeymap ../instfiles/km-0407.ini # Italy 'it' 0x0410 setxkbmap -model pc104 -layout it ./xrdp-genkeymap ../instfiles/km-0410.ini # Russia 'ru' 0x0419 setxkbmap -model pc104 -layout ru ./xrdp-genkeymap ../instfiles/km-0419.ini # Sweden 'se' 0x041d setxkbmap -model pc104 -layout se ./xrdp-genkeymap ../instfiles/km-041d.ini # set back to en-us setxkbmap -model pc104 -layout us xrdp-0.6.0/genkeymap/genkeymap.c000066400000000000000000000055461203155130500166030ustar00rootroot00000000000000/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */ /* * genkeymap.c * Copyright (C) Ãdám Wallner 2008 * * You may 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. * * main.cc 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 main.cc. If not, write to: * The Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301, USA Updated Jay Sorg 2009 cs czech 0x405 de german 0x407 en-us us english 0x409 fr french 0x40c it italy 0x410 br Portuguese (Brazil) 0x416 ru russian 0x419 se swedish 0x41d en-uk uk english 0x809 */ #include #include #include #include #include #include int main(int argc, char **argv) { const char* programname; char text[256]; char* displayname = NULL; char* outfname; char* sections[5] = {"noshift", "shift", "altgr", "capslock", "shiftcapslock"}; int states[5] = {0, 1, 0x80, 2, 3}; int i; int idx; int char_count; int nbytes = 0; int unicode; Display* dpy; KeySym ks; FILE* outf; XKeyPressedEvent e; wchar_t wtext[256]; setlocale(LC_CTYPE, ""); programname = argv[0]; if (argc != 2) { fprintf(stderr, "Usage: %s out_filename\n", programname); fprintf(stderr, "Example: %s /etc/xrdp/km-0409.ini\n", programname); return 1; } outfname = argv[1]; dpy = XOpenDisplay(displayname); if (!dpy) { fprintf(stderr, "%s: unable to open display '%s'\n", programname, XDisplayName(displayname)); return 1; } outf = fopen(outfname, "w"); if (outf == NULL) { fprintf(stderr, "%s: unable to create file '%s'\n", programname, outfname); XCloseDisplay(dpy); return 1; } memset(&e, 0, sizeof(e)); e.type = KeyPress; e.serial = 16; e.send_event = True; e.display = dpy; e.same_screen = True; for (idx = 0; idx < 5; idx++) /* Sections and states */ { fprintf(outf, "[%s]\n", sections[idx]); e.state = states[idx]; for (i = 8; i <= 137; i++) /* Keycodes */ { e.keycode = i; nbytes = XLookupString(&e, text, 255, &ks, NULL); text[nbytes] = 0; char_count = mbstowcs(wtext, text, 255); unicode = 0; if (char_count == 1) { unicode = wtext[0]; } fprintf(outf, "Key%d=%d:%d\n", i, (int) ks, unicode); } if (idx != 4) { fprintf(outf, "\n"); } } XCloseDisplay(dpy); fclose(outf); return 0; } xrdp-0.6.0/genkeymap/readme.txt000066400000000000000000000015621203155130500164470ustar00rootroot00000000000000 crating a new keymap file. The names of the files are km-xxxx.ini where the xxx is replaces ny the hex number of the layout of interest. The files have 5 section [noshift], [shift], [altgr], [capslock], [shiftcapslock] In each section there are multiple lines for each key An example line looks like Key10=49:49 In this line, 10 is the X11 scancode, the first 49 is the keysym value, the second 49 if the unicode value of the key. This is the definition for the 'noshift' '1' key on a en-us keyboard. In this case, the keysym and the unicode value are the same. Here is an example where they are not. This is the definition for the backspace key. Key22=65288:8 And this is the star on the keypad Key63=65450:42 To create a new file run xrdp-genkeymap filename Example ./xrdp-genkeymap /etc/xrdp/km-0409.ini Note: You need to have rights to the /etc/xrdp directory. xrdp-0.6.0/install.txt000066400000000000000000000026731203155130500147040ustar00rootroot00000000000000 Installation directions for xrdp. Things you need to compile and install. Most systems don't have these installed by default. gcc and make Header files for pam Header files for openssl You can build sesman without pam, there is a Makefile parameter for that. I also have a replacement ssl_calls.c to avoid the openssl dependency email me(Jay) for it or see http://server1.xrdp.org/xrdp/openssl. Due to the licence, I can't include it in this project. http://server1.xrdp.org/xrdp/openssl/ unpackage the tarball tar -zxvf xrdp-0.1.tar.gz this will create a folder xrdp switch to the xrdp folder(cd xrdp) run make as root, run make install This will install most of the files in /usr/local/xrdp. Some files install in /etc/xrdp. These are configuation files. files and location /usr/local/xrdp/startwm.sh - script that starts the window manager You may need to edit this file to run your window manager. /etc/sesman.ini - sesman configuration file /etc/rsakeys.ini - rsa stuff /etc/xrdp.ini - xrdp configuration file /var/run/sesman.pid /var/rub/xrdp.pid Sesman and xrdp both have to be running as root. You should set them to start when the system starts. You can use xrdp_control.sh script to start them. To completely remove xrdp remove directory /usr/local/xrdp remove directory /etc/xrdp remove file /var/run/xrdp.pid remove file /var/run/sesman.pid remove any startup links added to /etc/init.d or /etc/rcX.d jay.sorg@gmail.com xrdp-0.6.0/instfiles/000077500000000000000000000000001203155130500144655ustar00rootroot00000000000000xrdp-0.6.0/instfiles/Makefile.am000066400000000000000000000005561203155130500165270ustar00rootroot00000000000000EXTRA_DIST = xrdp.sh km-0407.ini km-0409.ini km-040c.ini km-0410.ini km-0419.ini km-041d.ini SUBDIRS = \ pam.d startscriptdir=$(sysconfdir)/xrdp startscript_DATA = \ xrdp.sh \ km-0407.ini \ km-0409.ini \ km-040c.ini \ km-0410.ini \ km-0419.ini \ km-041d.ini # must be tab below install-data-hook: chmod 755 $(DESTDIR)$(sysconfdir)/xrdp/xrdp.sh xrdp-0.6.0/instfiles/km-0407.ini000066400000000000000000000210641203155130500161700ustar00rootroot00000000000000[noshift] Key8=0:0 Key9=65307:27 Key10=49:49 Key11=50:50 Key12=51:51 Key13=52:52 Key14=53:53 Key15=54:54 Key16=55:55 Key17=56:56 Key18=57:57 Key19=48:48 Key20=223:223 Key21=65105:180 Key22=65288:8 Key23=65289:9 Key24=113:113 Key25=119:119 Key26=101:101 Key27=114:114 Key28=116:116 Key29=122:122 Key30=117:117 Key31=105:105 Key32=111:111 Key33=112:112 Key34=252:252 Key35=43:43 Key36=65293:13 Key37=65507:0 Key38=97:97 Key39=115:115 Key40=100:100 Key41=102:102 Key42=103:103 Key43=104:104 Key44=106:106 Key45=107:107 Key46=108:108 Key47=246:246 Key48=228:228 Key49=65106:94 Key50=65505:0 Key51=35:35 Key52=121:121 Key53=120:120 Key54=99:99 Key55=118:118 Key56=98:98 Key57=110:110 Key58=109:109 Key59=44:44 Key60=46:46 Key61=45:45 Key62=65506:0 Key63=65450:42 Key64=65513:0 Key65=32:32 Key66=65509:0 Key67=65470:0 Key68=65471:0 Key69=65472:0 Key70=65473:0 Key71=65474:0 Key72=65475:0 Key73=65476:0 Key74=65477:0 Key75=65478:0 Key76=65479:0 Key77=65407:0 Key78=65300:0 Key79=65429:0 Key80=65431:0 Key81=65434:0 Key82=65453:45 Key83=65430:0 Key84=65437:0 Key85=65432:0 Key86=65451:43 Key87=65436:0 Key88=65433:0 Key89=65435:0 Key90=65438:0 Key91=65439:0 Key92=0:0 Key93=65406:0 Key94=60:60 Key95=65480:0 Key96=65481:0 Key97=65360:0 Key98=65362:0 Key99=65365:0 Key100=65361:0 Key101=0:0 Key102=65363:0 Key103=65367:0 Key104=65364:0 Key105=65366:0 Key106=65379:0 Key107=65535:127 Key108=65421:13 Key109=65508:0 Key110=65299:0 Key111=65377:0 Key112=65455:47 Key113=65027:0 Key114=0:0 Key115=65515:0 Key116=65516:0 Key117=65383:0 Key118=0:0 Key119=0:0 Key120=0:0 Key121=0:0 Key122=0:0 Key123=0:0 Key124=65027:0 Key125=0:0 Key126=65469:61 Key127=0:0 Key128=0:0 Key129=0:0 Key130=0:0 Key131=0:0 Key132=0:0 Key133=0:0 Key134=0:0 Key135=0:0 Key136=0:0 Key137=0:0 [shift] Key8=0:0 Key9=65307:27 Key10=33:33 Key11=34:34 Key12=167:167 Key13=36:36 Key14=37:37 Key15=38:38 Key16=47:47 Key17=40:40 Key18=41:41 Key19=61:61 Key20=63:63 Key21=65104:96 Key22=65288:8 Key23=65056:0 Key24=81:81 Key25=87:87 Key26=69:69 Key27=82:82 Key28=84:84 Key29=90:90 Key30=85:85 Key31=73:73 Key32=79:79 Key33=80:80 Key34=220:220 Key35=42:42 Key36=65293:13 Key37=65507:0 Key38=65:65 Key39=83:83 Key40=68:68 Key41=70:70 Key42=71:71 Key43=72:72 Key44=74:74 Key45=75:75 Key46=76:76 Key47=214:214 Key48=196:196 Key49=176:176 Key50=65505:0 Key51=39:39 Key52=89:89 Key53=88:88 Key54=67:67 Key55=86:86 Key56=66:66 Key57=78:78 Key58=77:77 Key59=59:59 Key60=58:58 Key61=95:95 Key62=65506:0 Key63=65450:42 Key64=65511:0 Key65=32:32 Key66=65509:0 Key67=65470:0 Key68=65471:0 Key69=65472:0 Key70=65473:0 Key71=65474:0 Key72=65475:0 Key73=65476:0 Key74=65477:0 Key75=65478:0 Key76=65479:0 Key77=65273:0 Key78=65300:0 Key79=65463:55 Key80=65464:56 Key81=65465:57 Key82=65453:45 Key83=65460:52 Key84=65461:53 Key85=65462:54 Key86=65451:43 Key87=65457:49 Key88=65458:50 Key89=65459:51 Key90=65456:48 Key91=65452:44 Key92=0:0 Key93=65406:0 Key94=62:62 Key95=65480:0 Key96=65481:0 Key97=65360:0 Key98=65362:0 Key99=65365:0 Key100=65361:0 Key101=0:0 Key102=65363:0 Key103=65367:0 Key104=65364:0 Key105=65366:0 Key106=65379:0 Key107=65535:127 Key108=65421:13 Key109=65508:0 Key110=65299:0 Key111=65377:0 Key112=65455:47 Key113=65027:0 Key114=0:0 Key115=65515:0 Key116=65516:0 Key117=65383:0 Key118=0:0 Key119=0:0 Key120=0:0 Key121=0:0 Key122=0:0 Key123=0:0 Key124=65027:0 Key125=65513:0 Key126=65469:61 Key127=65515:0 Key128=65517:0 Key129=0:0 Key130=0:0 Key131=0:0 Key132=0:0 Key133=0:0 Key134=0:0 Key135=0:0 Key136=0:0 Key137=0:0 [altgr] Key8=0:0 Key9=65307:27 Key10=185:185 Key11=178:178 Key12=179:179 Key13=188:188 Key14=189:189 Key15=172:172 Key16=123:123 Key17=91:91 Key18=93:93 Key19=125:125 Key20=92:92 Key21=65115:184 Key22=65288:8 Key23=65289:9 Key24=64:64 Key25=435:322 Key26=8364:8364 Key27=182:182 Key28=956:359 Key29=2299:8592 Key30=2302:8595 Key31=2301:8594 Key32=248:248 Key33=254:254 Key34=65111:168 Key35=65107:126 Key36=65293:13 Key37=65507:0 Key38=230:230 Key39=223:223 Key40=240:240 Key41=496:273 Key42=959:331 Key43=689:295 Key44=106:106 Key45=930:312 Key46=435:322 Key47=65113:733 Key48=65106:94 Key49=172:172 Key50=65505:0 Key51=65104:96 Key52=171:171 Key53=187:187 Key54=162:162 Key55=2770:8220 Key56=2771:8221 Key57=110:110 Key58=181:181 Key59=2211:0 Key60=183:183 Key61=65120:0 Key62=65506:0 Key63=65450:42 Key64=65513:0 Key65=32:32 Key66=65509:0 Key67=65470:0 Key68=65471:0 Key69=65472:0 Key70=65473:0 Key71=65474:0 Key72=65475:0 Key73=65476:0 Key74=65477:0 Key75=65478:0 Key76=65479:0 Key77=65407:0 Key78=65300:0 Key79=65429:0 Key80=65431:0 Key81=65434:0 Key82=65453:45 Key83=65430:0 Key84=65437:0 Key85=65432:0 Key86=65451:43 Key87=65436:0 Key88=65433:0 Key89=65435:0 Key90=65438:0 Key91=65439:0 Key92=0:0 Key93=65406:0 Key94=124:124 Key95=65480:0 Key96=65481:0 Key97=65360:0 Key98=65362:0 Key99=65365:0 Key100=65361:0 Key101=0:0 Key102=65363:0 Key103=65367:0 Key104=65364:0 Key105=65366:0 Key106=65379:0 Key107=65535:127 Key108=65421:13 Key109=65508:0 Key110=65299:0 Key111=0:0 Key112=65455:47 Key113=65027:0 Key114=0:0 Key115=65515:0 Key116=65516:0 Key117=65383:0 Key118=0:0 Key119=0:0 Key120=0:0 Key121=0:0 Key122=0:0 Key123=0:0 Key124=65027:0 Key125=0:0 Key126=65469:61 Key127=0:0 Key128=0:0 Key129=0:0 Key130=0:0 Key131=0:0 Key132=0:0 Key133=0:0 Key134=0:0 Key135=0:0 Key136=0:0 Key137=0:0 [capslock] Key8=0:0 Key9=65307:27 Key10=49:49 Key11=50:50 Key12=51:51 Key13=52:52 Key14=53:53 Key15=54:54 Key16=55:55 Key17=56:56 Key18=57:57 Key19=48:48 Key20=223:223 Key21=65105:180 Key22=65288:8 Key23=65289:9 Key24=81:81 Key25=87:87 Key26=69:69 Key27=82:82 Key28=84:84 Key29=90:90 Key30=85:85 Key31=73:73 Key32=79:79 Key33=80:80 Key34=220:220 Key35=43:43 Key36=65293:13 Key37=65507:0 Key38=65:65 Key39=83:83 Key40=68:68 Key41=70:70 Key42=71:71 Key43=72:72 Key44=74:74 Key45=75:75 Key46=76:76 Key47=214:214 Key48=196:196 Key49=65106:94 Key50=65505:0 Key51=35:35 Key52=89:89 Key53=88:88 Key54=67:67 Key55=86:86 Key56=66:66 Key57=78:78 Key58=77:77 Key59=44:44 Key60=46:46 Key61=45:45 Key62=65506:0 Key63=65450:42 Key64=65513:0 Key65=32:32 Key66=65509:0 Key67=65470:0 Key68=65471:0 Key69=65472:0 Key70=65473:0 Key71=65474:0 Key72=65475:0 Key73=65476:0 Key74=65477:0 Key75=65478:0 Key76=65479:0 Key77=65407:0 Key78=65300:0 Key79=65429:0 Key80=65431:0 Key81=65434:0 Key82=65453:45 Key83=65430:0 Key84=65437:0 Key85=65432:0 Key86=65451:43 Key87=65436:0 Key88=65433:0 Key89=65435:0 Key90=65438:0 Key91=65439:0 Key92=0:0 Key93=65406:0 Key94=60:60 Key95=65480:0 Key96=65481:0 Key97=65360:0 Key98=65362:0 Key99=65365:0 Key100=65361:0 Key101=0:0 Key102=65363:0 Key103=65367:0 Key104=65364:0 Key105=65366:0 Key106=65379:0 Key107=65535:127 Key108=65421:13 Key109=65508:0 Key110=65299:0 Key111=65377:0 Key112=65455:47 Key113=65027:0 Key114=0:0 Key115=65515:0 Key116=65516:0 Key117=65383:0 Key118=0:0 Key119=0:0 Key120=0:0 Key121=0:0 Key122=0:0 Key123=0:0 Key124=65027:0 Key125=0:0 Key126=65469:61 Key127=0:0 Key128=0:0 Key129=0:0 Key130=0:0 Key131=0:0 Key132=0:0 Key133=0:0 Key134=0:0 Key135=0:0 Key136=0:0 Key137=0:0 [shiftcapslock] Key8=0:0 Key9=65307:27 Key10=33:33 Key11=34:34 Key12=167:167 Key13=36:36 Key14=37:37 Key15=38:38 Key16=47:47 Key17=40:40 Key18=41:41 Key19=61:61 Key20=63:63 Key21=65104:96 Key22=65288:8 Key23=65056:0 Key24=113:113 Key25=119:119 Key26=101:101 Key27=114:114 Key28=116:116 Key29=122:122 Key30=117:117 Key31=105:105 Key32=111:111 Key33=112:112 Key34=252:252 Key35=42:42 Key36=65293:13 Key37=65507:0 Key38=97:97 Key39=115:115 Key40=100:100 Key41=102:102 Key42=103:103 Key43=104:104 Key44=106:106 Key45=107:107 Key46=108:108 Key47=246:246 Key48=228:228 Key49=176:176 Key50=65505:0 Key51=39:39 Key52=121:121 Key53=120:120 Key54=99:99 Key55=118:118 Key56=98:98 Key57=110:110 Key58=109:109 Key59=59:59 Key60=58:58 Key61=95:95 Key62=65506:0 Key63=65450:42 Key64=65511:0 Key65=32:32 Key66=65509:0 Key67=65470:0 Key68=65471:0 Key69=65472:0 Key70=65473:0 Key71=65474:0 Key72=65475:0 Key73=65476:0 Key74=65477:0 Key75=65478:0 Key76=65479:0 Key77=65273:0 Key78=65300:0 Key79=65463:55 Key80=65464:56 Key81=65465:57 Key82=65453:45 Key83=65460:52 Key84=65461:53 Key85=65462:54 Key86=65451:43 Key87=65457:49 Key88=65458:50 Key89=65459:51 Key90=65456:48 Key91=65452:44 Key92=0:0 Key93=65406:0 Key94=62:62 Key95=65480:0 Key96=65481:0 Key97=65360:0 Key98=65362:0 Key99=65365:0 Key100=65361:0 Key101=0:0 Key102=65363:0 Key103=65367:0 Key104=65364:0 Key105=65366:0 Key106=65379:0 Key107=65535:127 Key108=65421:13 Key109=65508:0 Key110=65299:0 Key111=65377:0 Key112=65455:47 Key113=65027:0 Key114=0:0 Key115=65515:0 Key116=65516:0 Key117=65383:0 Key118=0:0 Key119=0:0 Key120=0:0 Key121=0:0 Key122=0:0 Key123=0:0 Key124=65027:0 Key125=65513:0 Key126=65469:61 Key127=65515:0 Key128=65517:0 Key129=0:0 Key130=0:0 Key131=0:0 Key132=0:0 Key133=0:0 Key134=0:0 Key135=0:0 Key136=0:0 Key137=0:0 xrdp-0.6.0/instfiles/km-0409.ini000066400000000000000000000207171203155130500161760ustar00rootroot00000000000000[noshift] Key8=0:0 Key9=65307:27 Key10=49:49 Key11=50:50 Key12=51:51 Key13=52:52 Key14=53:53 Key15=54:54 Key16=55:55 Key17=56:56 Key18=57:57 Key19=48:48 Key20=45:45 Key21=61:61 Key22=65288:8 Key23=65289:9 Key24=113:113 Key25=119:119 Key26=101:101 Key27=114:114 Key28=116:116 Key29=121:121 Key30=117:117 Key31=105:105 Key32=111:111 Key33=112:112 Key34=91:91 Key35=93:93 Key36=65293:13 Key37=65507:0 Key38=97:97 Key39=115:115 Key40=100:100 Key41=102:102 Key42=103:103 Key43=104:104 Key44=106:106 Key45=107:107 Key46=108:108 Key47=59:59 Key48=39:39 Key49=96:96 Key50=65505:0 Key51=92:92 Key52=122:122 Key53=120:120 Key54=99:99 Key55=118:118 Key56=98:98 Key57=110:110 Key58=109:109 Key59=44:44 Key60=46:46 Key61=47:47 Key62=65506:0 Key63=65450:42 Key64=65513:0 Key65=32:32 Key66=65509:0 Key67=65470:0 Key68=65471:0 Key69=65472:0 Key70=65473:0 Key71=65474:0 Key72=65475:0 Key73=65476:0 Key74=65477:0 Key75=65478:0 Key76=65479:0 Key77=65407:0 Key78=65300:0 Key79=65429:0 Key80=65431:0 Key81=65434:0 Key82=65453:45 Key83=65430:0 Key84=65437:0 Key85=65432:0 Key86=65451:43 Key87=65436:0 Key88=65433:0 Key89=65435:0 Key90=65438:0 Key91=65439:0 Key92=0:0 Key93=65406:0 Key94=60:60 Key95=65480:0 Key96=65481:0 Key97=65360:0 Key98=65362:0 Key99=65365:0 Key100=65361:0 Key101=0:0 Key102=65363:0 Key103=65367:0 Key104=65364:0 Key105=65366:0 Key106=65379:0 Key107=65535:127 Key108=65421:13 Key109=65508:0 Key110=65299:0 Key111=65377:0 Key112=65455:47 Key113=65514:0 Key114=0:0 Key115=65515:0 Key116=65516:0 Key117=65383:0 Key118=0:0 Key119=0:0 Key120=0:0 Key121=0:0 Key122=0:0 Key123=0:0 Key124=65027:0 Key125=0:0 Key126=65469:61 Key127=0:0 Key128=0:0 Key129=0:0 Key130=0:0 Key131=0:0 Key132=0:0 Key133=0:0 Key134=0:0 Key135=0:0 Key136=0:0 Key137=0:0 [shift] Key8=0:0 Key9=65307:27 Key10=33:33 Key11=64:64 Key12=35:35 Key13=36:36 Key14=37:37 Key15=94:94 Key16=38:38 Key17=42:42 Key18=40:40 Key19=41:41 Key20=95:95 Key21=43:43 Key22=65288:8 Key23=65056:0 Key24=81:81 Key25=87:87 Key26=69:69 Key27=82:82 Key28=84:84 Key29=89:89 Key30=85:85 Key31=73:73 Key32=79:79 Key33=80:80 Key34=123:123 Key35=125:125 Key36=65293:13 Key37=65507:0 Key38=65:65 Key39=83:83 Key40=68:68 Key41=70:70 Key42=71:71 Key43=72:72 Key44=74:74 Key45=75:75 Key46=76:76 Key47=58:58 Key48=34:34 Key49=126:126 Key50=65505:0 Key51=124:124 Key52=90:90 Key53=88:88 Key54=67:67 Key55=86:86 Key56=66:66 Key57=78:78 Key58=77:77 Key59=60:60 Key60=62:62 Key61=63:63 Key62=65506:0 Key63=65450:42 Key64=65511:0 Key65=32:32 Key66=65509:0 Key67=65470:0 Key68=65471:0 Key69=65472:0 Key70=65473:0 Key71=65474:0 Key72=65475:0 Key73=65476:0 Key74=65477:0 Key75=65478:0 Key76=65479:0 Key77=65273:0 Key78=65300:0 Key79=65463:55 Key80=65464:56 Key81=65465:57 Key82=65453:45 Key83=65460:52 Key84=65461:53 Key85=65462:54 Key86=65451:43 Key87=65457:49 Key88=65458:50 Key89=65459:51 Key90=65456:48 Key91=65454:46 Key92=0:0 Key93=65406:0 Key94=62:62 Key95=65480:0 Key96=65481:0 Key97=65360:0 Key98=65362:0 Key99=65365:0 Key100=65361:0 Key101=0:0 Key102=65363:0 Key103=65367:0 Key104=65364:0 Key105=65366:0 Key106=65379:0 Key107=65535:127 Key108=65421:13 Key109=65508:0 Key110=65299:0 Key111=65377:0 Key112=65455:47 Key113=65512:0 Key114=0:0 Key115=65515:0 Key116=65516:0 Key117=65383:0 Key118=0:0 Key119=0:0 Key120=0:0 Key121=0:0 Key122=0:0 Key123=0:0 Key124=65027:0 Key125=65513:0 Key126=65469:61 Key127=65515:0 Key128=65517:0 Key129=0:0 Key130=0:0 Key131=0:0 Key132=0:0 Key133=0:0 Key134=0:0 Key135=0:0 Key136=0:0 Key137=0:0 [altgr] Key8=0:0 Key9=65307:27 Key10=49:49 Key11=50:50 Key12=51:51 Key13=52:52 Key14=53:53 Key15=54:54 Key16=55:55 Key17=56:56 Key18=57:57 Key19=48:48 Key20=45:45 Key21=61:61 Key22=65288:8 Key23=65289:9 Key24=113:113 Key25=119:119 Key26=101:101 Key27=114:114 Key28=116:116 Key29=121:121 Key30=117:117 Key31=105:105 Key32=111:111 Key33=112:112 Key34=91:91 Key35=93:93 Key36=65293:13 Key37=65507:0 Key38=97:97 Key39=115:115 Key40=100:100 Key41=102:102 Key42=103:103 Key43=104:104 Key44=106:106 Key45=107:107 Key46=108:108 Key47=59:59 Key48=39:39 Key49=96:96 Key50=65505:0 Key51=92:92 Key52=122:122 Key53=120:120 Key54=99:99 Key55=118:118 Key56=98:98 Key57=110:110 Key58=109:109 Key59=44:44 Key60=46:46 Key61=47:47 Key62=65506:0 Key63=65450:42 Key64=65513:0 Key65=32:32 Key66=65509:0 Key67=65470:0 Key68=65471:0 Key69=65472:0 Key70=65473:0 Key71=65474:0 Key72=65475:0 Key73=65476:0 Key74=65477:0 Key75=65478:0 Key76=65479:0 Key77=65407:0 Key78=65300:0 Key79=65429:0 Key80=65431:0 Key81=65434:0 Key82=65453:45 Key83=65430:0 Key84=65437:0 Key85=65432:0 Key86=65451:43 Key87=65436:0 Key88=65433:0 Key89=65435:0 Key90=65438:0 Key91=65439:0 Key92=0:0 Key93=65406:0 Key94=124:124 Key95=65480:0 Key96=65481:0 Key97=65360:0 Key98=65362:0 Key99=65365:0 Key100=65361:0 Key101=0:0 Key102=65363:0 Key103=65367:0 Key104=65364:0 Key105=65366:0 Key106=65379:0 Key107=65535:127 Key108=65421:13 Key109=65508:0 Key110=65299:0 Key111=0:0 Key112=65455:47 Key113=65514:0 Key114=0:0 Key115=65515:0 Key116=65516:0 Key117=65383:0 Key118=0:0 Key119=0:0 Key120=0:0 Key121=0:0 Key122=0:0 Key123=0:0 Key124=65027:0 Key125=0:0 Key126=65469:61 Key127=0:0 Key128=0:0 Key129=0:0 Key130=0:0 Key131=0:0 Key132=0:0 Key133=0:0 Key134=0:0 Key135=0:0 Key136=0:0 Key137=0:0 [capslock] Key8=0:0 Key9=65307:27 Key10=49:49 Key11=50:50 Key12=51:51 Key13=52:52 Key14=53:53 Key15=54:54 Key16=55:55 Key17=56:56 Key18=57:57 Key19=48:48 Key20=45:45 Key21=61:61 Key22=65288:8 Key23=65289:9 Key24=81:81 Key25=87:87 Key26=69:69 Key27=82:82 Key28=84:84 Key29=89:89 Key30=85:85 Key31=73:73 Key32=79:79 Key33=80:80 Key34=91:91 Key35=93:93 Key36=65293:13 Key37=65507:0 Key38=65:65 Key39=83:83 Key40=68:68 Key41=70:70 Key42=71:71 Key43=72:72 Key44=74:74 Key45=75:75 Key46=76:76 Key47=59:59 Key48=39:39 Key49=96:96 Key50=65505:0 Key51=92:92 Key52=90:90 Key53=88:88 Key54=67:67 Key55=86:86 Key56=66:66 Key57=78:78 Key58=77:77 Key59=44:44 Key60=46:46 Key61=47:47 Key62=65506:0 Key63=65450:42 Key64=65513:0 Key65=32:32 Key66=65509:0 Key67=65470:0 Key68=65471:0 Key69=65472:0 Key70=65473:0 Key71=65474:0 Key72=65475:0 Key73=65476:0 Key74=65477:0 Key75=65478:0 Key76=65479:0 Key77=65407:0 Key78=65300:0 Key79=65429:0 Key80=65431:0 Key81=65434:0 Key82=65453:45 Key83=65430:0 Key84=65437:0 Key85=65432:0 Key86=65451:43 Key87=65436:0 Key88=65433:0 Key89=65435:0 Key90=65438:0 Key91=65439:0 Key92=0:0 Key93=65406:0 Key94=60:60 Key95=65480:0 Key96=65481:0 Key97=65360:0 Key98=65362:0 Key99=65365:0 Key100=65361:0 Key101=0:0 Key102=65363:0 Key103=65367:0 Key104=65364:0 Key105=65366:0 Key106=65379:0 Key107=65535:127 Key108=65421:13 Key109=65508:0 Key110=65299:0 Key111=65377:0 Key112=65455:47 Key113=65514:0 Key114=0:0 Key115=65515:0 Key116=65516:0 Key117=65383:0 Key118=0:0 Key119=0:0 Key120=0:0 Key121=0:0 Key122=0:0 Key123=0:0 Key124=65027:0 Key125=0:0 Key126=65469:61 Key127=0:0 Key128=0:0 Key129=0:0 Key130=0:0 Key131=0:0 Key132=0:0 Key133=0:0 Key134=0:0 Key135=0:0 Key136=0:0 Key137=0:0 [shiftcapslock] Key8=0:0 Key9=65307:27 Key10=33:33 Key11=64:64 Key12=35:35 Key13=36:36 Key14=37:37 Key15=94:94 Key16=38:38 Key17=42:42 Key18=40:40 Key19=41:41 Key20=95:95 Key21=43:43 Key22=65288:8 Key23=65056:0 Key24=113:113 Key25=119:119 Key26=101:101 Key27=114:114 Key28=116:116 Key29=121:121 Key30=117:117 Key31=105:105 Key32=111:111 Key33=112:112 Key34=123:123 Key35=125:125 Key36=65293:13 Key37=65507:0 Key38=97:97 Key39=115:115 Key40=100:100 Key41=102:102 Key42=103:103 Key43=104:104 Key44=106:106 Key45=107:107 Key46=108:108 Key47=58:58 Key48=34:34 Key49=126:126 Key50=65505:0 Key51=124:124 Key52=122:122 Key53=120:120 Key54=99:99 Key55=118:118 Key56=98:98 Key57=110:110 Key58=109:109 Key59=60:60 Key60=62:62 Key61=63:63 Key62=65506:0 Key63=65450:42 Key64=65511:0 Key65=32:32 Key66=65509:0 Key67=65470:0 Key68=65471:0 Key69=65472:0 Key70=65473:0 Key71=65474:0 Key72=65475:0 Key73=65476:0 Key74=65477:0 Key75=65478:0 Key76=65479:0 Key77=65273:0 Key78=65300:0 Key79=65463:55 Key80=65464:56 Key81=65465:57 Key82=65453:45 Key83=65460:52 Key84=65461:53 Key85=65462:54 Key86=65451:43 Key87=65457:49 Key88=65458:50 Key89=65459:51 Key90=65456:48 Key91=65454:46 Key92=0:0 Key93=65406:0 Key94=62:62 Key95=65480:0 Key96=65481:0 Key97=65360:0 Key98=65362:0 Key99=65365:0 Key100=65361:0 Key101=0:0 Key102=65363:0 Key103=65367:0 Key104=65364:0 Key105=65366:0 Key106=65379:0 Key107=65535:127 Key108=65421:13 Key109=65508:0 Key110=65299:0 Key111=65377:0 Key112=65455:47 Key113=65512:0 Key114=0:0 Key115=65515:0 Key116=65516:0 Key117=65383:0 Key118=0:0 Key119=0:0 Key120=0:0 Key121=0:0 Key122=0:0 Key123=0:0 Key124=65027:0 Key125=65513:0 Key126=65469:61 Key127=65515:0 Key128=65517:0 Key129=0:0 Key130=0:0 Key131=0:0 Key132=0:0 Key133=0:0 Key134=0:0 Key135=0:0 Key136=0:0 Key137=0:0 xrdp-0.6.0/instfiles/km-040c.ini000066400000000000000000000210501203155130500162370ustar00rootroot00000000000000[noshift] Key8=0:0 Key9=65307:27 Key10=38:38 Key11=233:233 Key12=34:34 Key13=39:39 Key14=40:40 Key15=45:45 Key16=232:232 Key17=95:95 Key18=231:231 Key19=224:224 Key20=41:41 Key21=61:61 Key22=65288:8 Key23=65289:9 Key24=97:97 Key25=122:122 Key26=101:101 Key27=114:114 Key28=116:116 Key29=121:121 Key30=117:117 Key31=105:105 Key32=111:111 Key33=112:112 Key34=65106:94 Key35=36:36 Key36=65293:13 Key37=65507:0 Key38=113:113 Key39=115:115 Key40=100:100 Key41=102:102 Key42=103:103 Key43=104:104 Key44=106:106 Key45=107:107 Key46=108:108 Key47=109:109 Key48=249:249 Key49=178:178 Key50=65505:0 Key51=42:42 Key52=119:119 Key53=120:120 Key54=99:99 Key55=118:118 Key56=98:98 Key57=110:110 Key58=44:44 Key59=59:59 Key60=58:58 Key61=33:33 Key62=65506:0 Key63=65450:42 Key64=65513:0 Key65=32:32 Key66=65509:0 Key67=65470:0 Key68=65471:0 Key69=65472:0 Key70=65473:0 Key71=65474:0 Key72=65475:0 Key73=65476:0 Key74=65477:0 Key75=65478:0 Key76=65479:0 Key77=65407:0 Key78=65300:0 Key79=65429:0 Key80=65431:0 Key81=65434:0 Key82=65453:45 Key83=65430:0 Key84=65437:0 Key85=65432:0 Key86=65451:43 Key87=65436:0 Key88=65433:0 Key89=65435:0 Key90=65438:0 Key91=65439:0 Key92=0:0 Key93=65406:0 Key94=60:60 Key95=65480:0 Key96=65481:0 Key97=65360:0 Key98=65362:0 Key99=65365:0 Key100=65361:0 Key101=0:0 Key102=65363:0 Key103=65367:0 Key104=65364:0 Key105=65366:0 Key106=65379:0 Key107=65535:127 Key108=65421:13 Key109=65508:0 Key110=65299:0 Key111=65377:0 Key112=65455:47 Key113=65027:0 Key114=0:0 Key115=65515:0 Key116=65516:0 Key117=65383:0 Key118=0:0 Key119=0:0 Key120=0:0 Key121=0:0 Key122=0:0 Key123=0:0 Key124=65027:0 Key125=0:0 Key126=65469:61 Key127=0:0 Key128=0:0 Key129=0:0 Key130=0:0 Key131=0:0 Key132=0:0 Key133=0:0 Key134=0:0 Key135=0:0 Key136=0:0 Key137=0:0 [shift] Key8=0:0 Key9=65307:27 Key10=49:49 Key11=50:50 Key12=51:51 Key13=52:52 Key14=53:53 Key15=54:54 Key16=55:55 Key17=56:56 Key18=57:57 Key19=48:48 Key20=176:176 Key21=43:43 Key22=65288:8 Key23=65056:0 Key24=65:65 Key25=90:90 Key26=69:69 Key27=82:82 Key28=84:84 Key29=89:89 Key30=85:85 Key31=73:73 Key32=79:79 Key33=80:80 Key34=65111:168 Key35=163:163 Key36=65293:13 Key37=65507:0 Key38=81:81 Key39=83:83 Key40=68:68 Key41=70:70 Key42=71:71 Key43=72:72 Key44=74:74 Key45=75:75 Key46=76:76 Key47=77:77 Key48=37:37 Key49=126:126 Key50=65505:0 Key51=181:181 Key52=87:87 Key53=88:88 Key54=67:67 Key55=86:86 Key56=66:66 Key57=78:78 Key58=63:63 Key59=46:46 Key60=47:47 Key61=167:167 Key62=65506:0 Key63=65450:42 Key64=65511:0 Key65=32:32 Key66=65509:0 Key67=65470:0 Key68=65471:0 Key69=65472:0 Key70=65473:0 Key71=65474:0 Key72=65475:0 Key73=65476:0 Key74=65477:0 Key75=65478:0 Key76=65479:0 Key77=65273:0 Key78=65300:0 Key79=65463:55 Key80=65464:56 Key81=65465:57 Key82=65453:45 Key83=65460:52 Key84=65461:53 Key85=65462:54 Key86=65451:43 Key87=65457:49 Key88=65458:50 Key89=65459:51 Key90=65456:48 Key91=65454:46 Key92=0:0 Key93=65406:0 Key94=62:62 Key95=65480:0 Key96=65481:0 Key97=65360:0 Key98=65362:0 Key99=65365:0 Key100=65361:0 Key101=0:0 Key102=65363:0 Key103=65367:0 Key104=65364:0 Key105=65366:0 Key106=65379:0 Key107=65535:127 Key108=65421:13 Key109=65508:0 Key110=65299:0 Key111=65377:0 Key112=65455:47 Key113=65027:0 Key114=0:0 Key115=65515:0 Key116=65516:0 Key117=65383:0 Key118=0:0 Key119=0:0 Key120=0:0 Key121=0:0 Key122=0:0 Key123=0:0 Key124=65027:0 Key125=65513:0 Key126=65469:61 Key127=65515:0 Key128=65517:0 Key129=0:0 Key130=0:0 Key131=0:0 Key132=0:0 Key133=0:0 Key134=0:0 Key135=0:0 Key136=0:0 Key137=0:0 [altgr] Key8=0:0 Key9=65307:27 Key10=185:185 Key11=126:126 Key12=35:35 Key13=123:123 Key14=91:91 Key15=124:124 Key16=96:96 Key17=92:92 Key18=94:94 Key19=64:64 Key20=93:93 Key21=125:125 Key22=65288:8 Key23=65289:9 Key24=230:230 Key25=171:171 Key26=8364:8364 Key27=182:182 Key28=956:359 Key29=2299:8592 Key30=2302:8595 Key31=2301:8594 Key32=248:248 Key33=254:254 Key34=65111:168 Key35=164:164 Key36=65293:13 Key37=65507:0 Key38=64:64 Key39=223:223 Key40=240:240 Key41=496:273 Key42=959:331 Key43=689:295 Key44=106:106 Key45=930:312 Key46=435:322 Key47=181:181 Key48=65106:94 Key49=172:172 Key50=65505:0 Key51=65104:96 Key52=435:322 Key53=187:187 Key54=162:162 Key55=2770:8220 Key56=2771:8221 Key57=110:110 Key58=65105:180 Key59=2211:0 Key60=183:183 Key61=65120:0 Key62=65506:0 Key63=65450:42 Key64=65513:0 Key65=32:32 Key66=65509:0 Key67=65470:0 Key68=65471:0 Key69=65472:0 Key70=65473:0 Key71=65474:0 Key72=65475:0 Key73=65476:0 Key74=65477:0 Key75=65478:0 Key76=65479:0 Key77=65407:0 Key78=65300:0 Key79=65429:0 Key80=65431:0 Key81=65434:0 Key82=65453:45 Key83=65430:0 Key84=65437:0 Key85=65432:0 Key86=65451:43 Key87=65436:0 Key88=65433:0 Key89=65435:0 Key90=65438:0 Key91=65439:0 Key92=0:0 Key93=65406:0 Key94=124:124 Key95=65480:0 Key96=65481:0 Key97=65360:0 Key98=65362:0 Key99=65365:0 Key100=65361:0 Key101=0:0 Key102=65363:0 Key103=65367:0 Key104=65364:0 Key105=65366:0 Key106=65379:0 Key107=65535:127 Key108=65421:13 Key109=65508:0 Key110=65299:0 Key111=0:0 Key112=65455:47 Key113=65027:0 Key114=0:0 Key115=65515:0 Key116=65516:0 Key117=65383:0 Key118=0:0 Key119=0:0 Key120=0:0 Key121=0:0 Key122=0:0 Key123=0:0 Key124=65027:0 Key125=0:0 Key126=65469:61 Key127=0:0 Key128=0:0 Key129=0:0 Key130=0:0 Key131=0:0 Key132=0:0 Key133=0:0 Key134=0:0 Key135=0:0 Key136=0:0 Key137=0:0 [capslock] Key8=0:0 Key9=65307:27 Key10=38:38 Key11=201:201 Key12=34:34 Key13=39:39 Key14=40:40 Key15=45:45 Key16=200:200 Key17=95:95 Key18=199:199 Key19=192:192 Key20=41:41 Key21=61:61 Key22=65288:8 Key23=65289:9 Key24=65:65 Key25=90:90 Key26=69:69 Key27=82:82 Key28=84:84 Key29=89:89 Key30=85:85 Key31=73:73 Key32=79:79 Key33=80:80 Key34=65106:94 Key35=36:36 Key36=65293:13 Key37=65507:0 Key38=81:81 Key39=83:83 Key40=68:68 Key41=70:70 Key42=71:71 Key43=72:72 Key44=74:74 Key45=75:75 Key46=76:76 Key47=77:77 Key48=217:217 Key49=178:178 Key50=65505:0 Key51=42:42 Key52=87:87 Key53=88:88 Key54=67:67 Key55=86:86 Key56=66:66 Key57=78:78 Key58=44:44 Key59=59:59 Key60=58:58 Key61=33:33 Key62=65506:0 Key63=65450:42 Key64=65513:0 Key65=32:32 Key66=65509:0 Key67=65470:0 Key68=65471:0 Key69=65472:0 Key70=65473:0 Key71=65474:0 Key72=65475:0 Key73=65476:0 Key74=65477:0 Key75=65478:0 Key76=65479:0 Key77=65407:0 Key78=65300:0 Key79=65429:0 Key80=65431:0 Key81=65434:0 Key82=65453:45 Key83=65430:0 Key84=65437:0 Key85=65432:0 Key86=65451:43 Key87=65436:0 Key88=65433:0 Key89=65435:0 Key90=65438:0 Key91=65439:0 Key92=0:0 Key93=65406:0 Key94=60:60 Key95=65480:0 Key96=65481:0 Key97=65360:0 Key98=65362:0 Key99=65365:0 Key100=65361:0 Key101=0:0 Key102=65363:0 Key103=65367:0 Key104=65364:0 Key105=65366:0 Key106=65379:0 Key107=65535:127 Key108=65421:13 Key109=65508:0 Key110=65299:0 Key111=65377:0 Key112=65455:47 Key113=65027:0 Key114=0:0 Key115=65515:0 Key116=65516:0 Key117=65383:0 Key118=0:0 Key119=0:0 Key120=0:0 Key121=0:0 Key122=0:0 Key123=0:0 Key124=65027:0 Key125=0:0 Key126=65469:61 Key127=0:0 Key128=0:0 Key129=0:0 Key130=0:0 Key131=0:0 Key132=0:0 Key133=0:0 Key134=0:0 Key135=0:0 Key136=0:0 Key137=0:0 [shiftcapslock] Key8=0:0 Key9=65307:27 Key10=49:49 Key11=50:50 Key12=51:51 Key13=52:52 Key14=53:53 Key15=54:54 Key16=55:55 Key17=56:56 Key18=57:57 Key19=48:48 Key20=176:176 Key21=43:43 Key22=65288:8 Key23=65056:0 Key24=97:97 Key25=122:122 Key26=101:101 Key27=114:114 Key28=116:116 Key29=121:121 Key30=117:117 Key31=105:105 Key32=111:111 Key33=112:112 Key34=65111:168 Key35=163:163 Key36=65293:13 Key37=65507:0 Key38=113:113 Key39=115:115 Key40=100:100 Key41=102:102 Key42=103:103 Key43=104:104 Key44=106:106 Key45=107:107 Key46=108:108 Key47=109:109 Key48=37:37 Key49=126:126 Key50=65505:0 Key51=924:0 Key52=119:119 Key53=120:120 Key54=99:99 Key55=118:118 Key56=98:98 Key57=110:110 Key58=63:63 Key59=46:46 Key60=47:47 Key61=167:167 Key62=65506:0 Key63=65450:42 Key64=65511:0 Key65=32:32 Key66=65509:0 Key67=65470:0 Key68=65471:0 Key69=65472:0 Key70=65473:0 Key71=65474:0 Key72=65475:0 Key73=65476:0 Key74=65477:0 Key75=65478:0 Key76=65479:0 Key77=65273:0 Key78=65300:0 Key79=65463:55 Key80=65464:56 Key81=65465:57 Key82=65453:45 Key83=65460:52 Key84=65461:53 Key85=65462:54 Key86=65451:43 Key87=65457:49 Key88=65458:50 Key89=65459:51 Key90=65456:48 Key91=65454:46 Key92=0:0 Key93=65406:0 Key94=62:62 Key95=65480:0 Key96=65481:0 Key97=65360:0 Key98=65362:0 Key99=65365:0 Key100=65361:0 Key101=0:0 Key102=65363:0 Key103=65367:0 Key104=65364:0 Key105=65366:0 Key106=65379:0 Key107=65535:127 Key108=65421:13 Key109=65508:0 Key110=65299:0 Key111=65377:0 Key112=65455:47 Key113=65027:0 Key114=0:0 Key115=65515:0 Key116=65516:0 Key117=65383:0 Key118=0:0 Key119=0:0 Key120=0:0 Key121=0:0 Key122=0:0 Key123=0:0 Key124=65027:0 Key125=65513:0 Key126=65469:61 Key127=65515:0 Key128=65517:0 Key129=0:0 Key130=0:0 Key131=0:0 Key132=0:0 Key133=0:0 Key134=0:0 Key135=0:0 Key136=0:0 Key137=0:0 xrdp-0.6.0/instfiles/km-0410.ini000066400000000000000000000210341203155130500161570ustar00rootroot00000000000000[noshift] Key8=0:0 Key9=65307:27 Key10=49:49 Key11=50:50 Key12=51:51 Key13=52:52 Key14=53:53 Key15=54:54 Key16=55:55 Key17=56:56 Key18=57:57 Key19=48:48 Key20=39:39 Key21=236:236 Key22=65288:8 Key23=65289:9 Key24=113:113 Key25=119:119 Key26=101:101 Key27=114:114 Key28=116:116 Key29=121:121 Key30=117:117 Key31=105:105 Key32=111:111 Key33=112:112 Key34=232:232 Key35=43:43 Key36=65293:13 Key37=65507:0 Key38=97:97 Key39=115:115 Key40=100:100 Key41=102:102 Key42=103:103 Key43=104:104 Key44=106:106 Key45=107:107 Key46=108:108 Key47=242:242 Key48=224:224 Key49=92:92 Key50=65505:0 Key51=249:249 Key52=122:122 Key53=120:120 Key54=99:99 Key55=118:118 Key56=98:98 Key57=110:110 Key58=109:109 Key59=44:44 Key60=46:46 Key61=45:45 Key62=65506:0 Key63=65450:42 Key64=65513:0 Key65=32:32 Key66=65509:0 Key67=65470:0 Key68=65471:0 Key69=65472:0 Key70=65473:0 Key71=65474:0 Key72=65475:0 Key73=65476:0 Key74=65477:0 Key75=65478:0 Key76=65479:0 Key77=65407:0 Key78=65300:0 Key79=65429:0 Key80=65431:0 Key81=65434:0 Key82=65453:45 Key83=65430:0 Key84=65437:0 Key85=65432:0 Key86=65451:43 Key87=65436:0 Key88=65433:0 Key89=65435:0 Key90=65438:0 Key91=65439:0 Key92=0:0 Key93=65406:0 Key94=60:60 Key95=65480:0 Key96=65481:0 Key97=65360:0 Key98=65362:0 Key99=65365:0 Key100=65361:0 Key101=0:0 Key102=65363:0 Key103=65367:0 Key104=65364:0 Key105=65366:0 Key106=65379:0 Key107=65535:127 Key108=65421:13 Key109=65508:0 Key110=65299:0 Key111=65377:0 Key112=65455:47 Key113=65027:0 Key114=0:0 Key115=65515:0 Key116=65516:0 Key117=65383:0 Key118=0:0 Key119=0:0 Key120=0:0 Key121=0:0 Key122=0:0 Key123=0:0 Key124=65027:0 Key125=0:0 Key126=65469:61 Key127=0:0 Key128=0:0 Key129=0:0 Key130=0:0 Key131=0:0 Key132=0:0 Key133=0:0 Key134=0:0 Key135=0:0 Key136=0:0 Key137=0:0 [shift] Key8=0:0 Key9=65307:27 Key10=33:33 Key11=34:34 Key12=163:163 Key13=36:36 Key14=37:37 Key15=38:38 Key16=47:47 Key17=40:40 Key18=41:41 Key19=61:61 Key20=63:63 Key21=94:94 Key22=65288:8 Key23=65056:0 Key24=81:81 Key25=87:87 Key26=69:69 Key27=82:82 Key28=84:84 Key29=89:89 Key30=85:85 Key31=73:73 Key32=79:79 Key33=80:80 Key34=233:233 Key35=42:42 Key36=65293:13 Key37=65507:0 Key38=65:65 Key39=83:83 Key40=68:68 Key41=70:70 Key42=71:71 Key43=72:72 Key44=74:74 Key45=75:75 Key46=76:76 Key47=231:231 Key48=176:176 Key49=124:124 Key50=65505:0 Key51=167:167 Key52=90:90 Key53=88:88 Key54=67:67 Key55=86:86 Key56=66:66 Key57=78:78 Key58=77:77 Key59=59:59 Key60=58:58 Key61=95:95 Key62=65506:0 Key63=65450:42 Key64=65511:0 Key65=32:32 Key66=65509:0 Key67=65470:0 Key68=65471:0 Key69=65472:0 Key70=65473:0 Key71=65474:0 Key72=65475:0 Key73=65476:0 Key74=65477:0 Key75=65478:0 Key76=65479:0 Key77=65273:0 Key78=65300:0 Key79=65463:55 Key80=65464:56 Key81=65465:57 Key82=65453:45 Key83=65460:52 Key84=65461:53 Key85=65462:54 Key86=65451:43 Key87=65457:49 Key88=65458:50 Key89=65459:51 Key90=65456:48 Key91=65454:46 Key92=0:0 Key93=65406:0 Key94=62:62 Key95=65480:0 Key96=65481:0 Key97=65360:0 Key98=65362:0 Key99=65365:0 Key100=65361:0 Key101=0:0 Key102=65363:0 Key103=65367:0 Key104=65364:0 Key105=65366:0 Key106=65379:0 Key107=65535:127 Key108=65421:13 Key109=65508:0 Key110=65299:0 Key111=65377:0 Key112=65455:47 Key113=65027:0 Key114=0:0 Key115=65515:0 Key116=65516:0 Key117=65383:0 Key118=0:0 Key119=0:0 Key120=0:0 Key121=0:0 Key122=0:0 Key123=0:0 Key124=65027:0 Key125=65513:0 Key126=65469:61 Key127=65515:0 Key128=65517:0 Key129=0:0 Key130=0:0 Key131=0:0 Key132=0:0 Key133=0:0 Key134=0:0 Key135=0:0 Key136=0:0 Key137=0:0 [altgr] Key8=0:0 Key9=65307:27 Key10=185:185 Key11=178:178 Key12=179:179 Key13=188:188 Key14=189:189 Key15=172:172 Key16=123:123 Key17=91:91 Key18=93:93 Key19=125:125 Key20=96:96 Key21=126:126 Key22=65288:8 Key23=65289:9 Key24=64:64 Key25=435:322 Key26=8364:8364 Key27=182:182 Key28=956:359 Key29=2299:8592 Key30=2302:8595 Key31=2301:8594 Key32=248:248 Key33=254:254 Key34=91:91 Key35=93:93 Key36=65293:13 Key37=65507:0 Key38=230:230 Key39=223:223 Key40=240:240 Key41=496:273 Key42=959:331 Key43=689:295 Key44=106:106 Key45=930:312 Key46=435:322 Key47=64:64 Key48=35:35 Key49=172:172 Key50=65505:0 Key51=65104:96 Key52=171:171 Key53=187:187 Key54=162:162 Key55=2770:8220 Key56=2771:8221 Key57=241:241 Key58=181:181 Key59=65105:180 Key60=183:183 Key61=65108:175 Key62=65506:0 Key63=65450:42 Key64=65513:0 Key65=32:32 Key66=65509:0 Key67=65470:0 Key68=65471:0 Key69=65472:0 Key70=65473:0 Key71=65474:0 Key72=65475:0 Key73=65476:0 Key74=65477:0 Key75=65478:0 Key76=65479:0 Key77=65407:0 Key78=65300:0 Key79=65429:0 Key80=65431:0 Key81=65434:0 Key82=65453:45 Key83=65430:0 Key84=65437:0 Key85=65432:0 Key86=65451:43 Key87=65436:0 Key88=65433:0 Key89=65435:0 Key90=65438:0 Key91=65439:0 Key92=0:0 Key93=65406:0 Key94=171:171 Key95=65480:0 Key96=65481:0 Key97=65360:0 Key98=65362:0 Key99=65365:0 Key100=65361:0 Key101=0:0 Key102=65363:0 Key103=65367:0 Key104=65364:0 Key105=65366:0 Key106=65379:0 Key107=65535:127 Key108=65421:13 Key109=65508:0 Key110=65299:0 Key111=0:0 Key112=65455:47 Key113=65027:0 Key114=0:0 Key115=65515:0 Key116=65516:0 Key117=65383:0 Key118=0:0 Key119=0:0 Key120=0:0 Key121=0:0 Key122=0:0 Key123=0:0 Key124=65027:0 Key125=0:0 Key126=65469:61 Key127=0:0 Key128=0:0 Key129=0:0 Key130=0:0 Key131=0:0 Key132=0:0 Key133=0:0 Key134=0:0 Key135=0:0 Key136=0:0 Key137=0:0 [capslock] Key8=0:0 Key9=65307:27 Key10=49:49 Key11=50:50 Key12=51:51 Key13=52:52 Key14=53:53 Key15=54:54 Key16=55:55 Key17=56:56 Key18=57:57 Key19=48:48 Key20=39:39 Key21=204:204 Key22=65288:8 Key23=65289:9 Key24=81:81 Key25=87:87 Key26=69:69 Key27=82:82 Key28=84:84 Key29=89:89 Key30=85:85 Key31=73:73 Key32=79:79 Key33=80:80 Key34=200:200 Key35=43:43 Key36=65293:13 Key37=65507:0 Key38=65:65 Key39=83:83 Key40=68:68 Key41=70:70 Key42=71:71 Key43=72:72 Key44=74:74 Key45=75:75 Key46=76:76 Key47=210:210 Key48=192:192 Key49=92:92 Key50=65505:0 Key51=217:217 Key52=90:90 Key53=88:88 Key54=67:67 Key55=86:86 Key56=66:66 Key57=78:78 Key58=77:77 Key59=44:44 Key60=46:46 Key61=45:45 Key62=65506:0 Key63=65450:42 Key64=65513:0 Key65=32:32 Key66=65509:0 Key67=65470:0 Key68=65471:0 Key69=65472:0 Key70=65473:0 Key71=65474:0 Key72=65475:0 Key73=65476:0 Key74=65477:0 Key75=65478:0 Key76=65479:0 Key77=65407:0 Key78=65300:0 Key79=65429:0 Key80=65431:0 Key81=65434:0 Key82=65453:45 Key83=65430:0 Key84=65437:0 Key85=65432:0 Key86=65451:43 Key87=65436:0 Key88=65433:0 Key89=65435:0 Key90=65438:0 Key91=65439:0 Key92=0:0 Key93=65406:0 Key94=60:60 Key95=65480:0 Key96=65481:0 Key97=65360:0 Key98=65362:0 Key99=65365:0 Key100=65361:0 Key101=0:0 Key102=65363:0 Key103=65367:0 Key104=65364:0 Key105=65366:0 Key106=65379:0 Key107=65535:127 Key108=65421:13 Key109=65508:0 Key110=65299:0 Key111=65377:0 Key112=65455:47 Key113=65027:0 Key114=0:0 Key115=65515:0 Key116=65516:0 Key117=65383:0 Key118=0:0 Key119=0:0 Key120=0:0 Key121=0:0 Key122=0:0 Key123=0:0 Key124=65027:0 Key125=0:0 Key126=65469:61 Key127=0:0 Key128=0:0 Key129=0:0 Key130=0:0 Key131=0:0 Key132=0:0 Key133=0:0 Key134=0:0 Key135=0:0 Key136=0:0 Key137=0:0 [shiftcapslock] Key8=0:0 Key9=65307:27 Key10=33:33 Key11=34:34 Key12=163:163 Key13=36:36 Key14=37:37 Key15=38:38 Key16=47:47 Key17=40:40 Key18=41:41 Key19=61:61 Key20=63:63 Key21=94:94 Key22=65288:8 Key23=65056:0 Key24=113:113 Key25=119:119 Key26=101:101 Key27=114:114 Key28=116:116 Key29=121:121 Key30=117:117 Key31=105:105 Key32=111:111 Key33=112:112 Key34=201:201 Key35=42:42 Key36=65293:13 Key37=65507:0 Key38=97:97 Key39=115:115 Key40=100:100 Key41=102:102 Key42=103:103 Key43=104:104 Key44=106:106 Key45=107:107 Key46=108:108 Key47=199:199 Key48=176:176 Key49=124:124 Key50=65505:0 Key51=167:167 Key52=122:122 Key53=120:120 Key54=99:99 Key55=118:118 Key56=98:98 Key57=110:110 Key58=109:109 Key59=59:59 Key60=58:58 Key61=95:95 Key62=65506:0 Key63=65450:42 Key64=65511:0 Key65=32:32 Key66=65509:0 Key67=65470:0 Key68=65471:0 Key69=65472:0 Key70=65473:0 Key71=65474:0 Key72=65475:0 Key73=65476:0 Key74=65477:0 Key75=65478:0 Key76=65479:0 Key77=65273:0 Key78=65300:0 Key79=65463:55 Key80=65464:56 Key81=65465:57 Key82=65453:45 Key83=65460:52 Key84=65461:53 Key85=65462:54 Key86=65451:43 Key87=65457:49 Key88=65458:50 Key89=65459:51 Key90=65456:48 Key91=65454:46 Key92=0:0 Key93=65406:0 Key94=62:62 Key95=65480:0 Key96=65481:0 Key97=65360:0 Key98=65362:0 Key99=65365:0 Key100=65361:0 Key101=0:0 Key102=65363:0 Key103=65367:0 Key104=65364:0 Key105=65366:0 Key106=65379:0 Key107=65535:127 Key108=65421:13 Key109=65508:0 Key110=65299:0 Key111=65377:0 Key112=65455:47 Key113=65027:0 Key114=0:0 Key115=65515:0 Key116=65516:0 Key117=65383:0 Key118=0:0 Key119=0:0 Key120=0:0 Key121=0:0 Key122=0:0 Key123=0:0 Key124=65027:0 Key125=65513:0 Key126=65469:61 Key127=65515:0 Key128=65517:0 Key129=0:0 Key130=0:0 Key131=0:0 Key132=0:0 Key133=0:0 Key134=0:0 Key135=0:0 Key136=0:0 Key137=0:0 xrdp-0.6.0/instfiles/km-0416.ini000066400000000000000000000217201203155130500161670ustar00rootroot00000000000000[noshift] Key8=0:0 Key9=65307:27 Key10=49:49 Key11=50:50 Key12=51:51 Key13=52:52 Key14=53:53 Key15=54:54 Key16=55:55 Key17=56:56 Key18=57:57 Key19=48:48 Key20=45:45 Key21=61:61 Key22=65288:8 Key23=65289:9 Key24=113:113 Key25=119:119 Key26=101:101 Key27=114:114 Key28=116:116 Key29=121:121 Key30=117:117 Key31=105:105 Key32=111:111 Key33=112:112 Key34=65105:180 Key35=91:91 Key36=65293:13 Key37=65507:0 Key38=97:97 Key39=115:115 Key40=100:100 Key41=102:102 Key42=103:103 Key43=104:104 Key44=106:106 Key45=107:107 Key46=108:108 Key47=231:231 Key48=65107:126 Key49=39:39 Key50=65505:0 Key51=93:93 Key52=122:122 Key53=120:120 Key54=99:99 Key55=118:118 Key56=98:98 Key57=110:110 Key58=109:109 Key59=44:44 Key60=46:46 Key61=59:59 Key62=65506:0 Key63=65450:42 Key64=65513:0 Key65=32:32 Key66=65509:0 Key67=65470:0 Key68=65471:0 Key69=65472:0 Key70=65473:0 Key71=65474:0 Key72=65475:0 Key73=65476:0 Key74=65477:0 Key75=65478:0 Key76=65479:0 Key77=65407:0 Key78=65300:0 Key79=65429:0 Key80=65431:0 Key81=65434:0 Key82=65453:45 Key83=65430:0 Key84=65437:0 Key85=65432:0 Key86=65451:43 Key87=65436:0 Key88=65433:0 Key89=65435:0 Key90=65438:0 Key91=65439:0 Key92=65027:0 Key93=0:0 Key94=92:92 Key95=65480:0 Key96=65481:0 Key97=47:47 Key98=65318:0 Key99=65317:0 Key100=65315:0 Key101=65319:0 Key102=65314:0 Key103=0:0 Key104=65421:13 Key105=65508:0 Key106=65455:47 Key107=65377:0 Key108=65027:0 Key109=65290:10 Key110=65360:0 Key111=65362:0 Key112=65365:0 Key113=65361:0 Key114=65363:0 Key115=65367:0 Key116=65364:0 Key117=65366:0 Key118=65379:0 Key119=65535:127 Key120=0:0 Key121=269025042:0 Key122=269025041:0 Key123=269025043:0 Key124=269025066:0 Key125=65469:61 Key126=177:177 Key127=65299:0 Key128=269025098:0 Key129=65454:46 Key130=65329:0 Key131=65332:0 Key132=0:0 Key133=65515:0 Key134=65516:0 Key135=65383:0 Key136=65385:0 Key137=65382:0 [shift] Key8=0:0 Key9=65307:27 Key10=33:33 Key11=64:64 Key12=35:35 Key13=36:36 Key14=37:37 Key15=65111:168 Key16=38:38 Key17=42:42 Key18=40:40 Key19=41:41 Key20=95:95 Key21=43:43 Key22=65288:8 Key23=65056:0 Key24=81:81 Key25=87:87 Key26=69:69 Key27=82:82 Key28=84:84 Key29=89:89 Key30=85:85 Key31=73:73 Key32=79:79 Key33=80:80 Key34=65104:96 Key35=123:123 Key36=65293:13 Key37=65507:0 Key38=65:65 Key39=83:83 Key40=68:68 Key41=70:70 Key42=71:71 Key43=72:72 Key44=74:74 Key45=75:75 Key46=76:76 Key47=199:199 Key48=65106:94 Key49=34:34 Key50=65505:0 Key51=125:125 Key52=90:90 Key53=88:88 Key54=67:67 Key55=86:86 Key56=66:66 Key57=78:78 Key58=77:77 Key59=60:60 Key60=62:62 Key61=58:58 Key62=65506:0 Key63=65450:42 Key64=65511:0 Key65=32:32 Key66=65509:0 Key67=65470:0 Key68=65471:0 Key69=65472:0 Key70=65473:0 Key71=65474:0 Key72=65475:0 Key73=65476:0 Key74=65477:0 Key75=65478:0 Key76=65479:0 Key77=65407:0 Key78=65300:0 Key79=65463:55 Key80=65464:56 Key81=65465:57 Key82=65453:45 Key83=65460:52 Key84=65461:53 Key85=65462:54 Key86=65451:43 Key87=65457:49 Key88=65458:50 Key89=65459:51 Key90=65456:48 Key91=65452:44 Key92=65027:0 Key93=0:0 Key94=124:124 Key95=65480:0 Key96=65481:0 Key97=63:63 Key98=65318:0 Key99=65317:0 Key100=65315:0 Key101=65319:0 Key102=65314:0 Key103=0:0 Key104=65421:13 Key105=65508:0 Key106=65455:47 Key107=65377:0 Key108=65027:0 Key109=65290:10 Key110=65360:0 Key111=65362:0 Key112=65365:0 Key113=65361:0 Key114=65363:0 Key115=65367:0 Key116=65364:0 Key117=65366:0 Key118=65379:0 Key119=65535:127 Key120=0:0 Key121=269025042:0 Key122=269025041:0 Key123=269025043:0 Key124=269025066:0 Key125=65469:61 Key126=177:177 Key127=65299:0 Key128=269025098:0 Key129=65454:46 Key130=65329:0 Key131=65332:0 Key132=0:0 Key133=65515:0 Key134=65516:0 Key135=65383:0 Key136=65385:0 Key137=65382:0 [altgr] Key8=0:0 Key9=65307:27 Key10=185:185 Key11=178:178 Key12=179:179 Key13=163:163 Key14=162:162 Key15=172:172 Key16=123:123 Key17=91:91 Key18=93:93 Key19=125:125 Key20=92:92 Key21=167:167 Key22=65288:8 Key23=65289:9 Key24=47:47 Key25=63:63 Key26=8364:8364 Key27=174:174 Key28=956:359 Key29=2299:8592 Key30=2302:8595 Key31=2301:8594 Key32=248:248 Key33=254:254 Key34=180:180 Key35=170:170 Key36=65293:13 Key37=65507:0 Key38=230:230 Key39=223:223 Key40=240:240 Key41=496:273 Key42=959:331 Key43=689:295 Key44=106:106 Key45=930:312 Key46=435:322 Key47=65105:180 Key48=126:126 Key49=172:172 Key50=65505:0 Key51=186:186 Key52=171:171 Key53=187:187 Key54=169:169 Key55=2770:8220 Key56=2771:8221 Key57=110:110 Key58=181:181 Key59=2211:0 Key60=183:183 Key61=65120:0 Key62=65506:0 Key63=65450:42 Key64=65513:0 Key65=32:32 Key66=65509:0 Key67=65470:0 Key68=65471:0 Key69=65472:0 Key70=65473:0 Key71=65474:0 Key72=65475:0 Key73=65476:0 Key74=65477:0 Key75=65478:0 Key76=65479:0 Key77=65407:0 Key78=65300:0 Key79=65429:0 Key80=65431:0 Key81=65434:0 Key82=65453:45 Key83=65430:0 Key84=65437:0 Key85=65432:0 Key86=65451:43 Key87=65436:0 Key88=65433:0 Key89=65435:0 Key90=65438:0 Key91=65439:0 Key92=65027:0 Key93=0:0 Key94=186:186 Key95=65480:0 Key96=65481:0 Key97=176:176 Key98=65318:0 Key99=65317:0 Key100=65315:0 Key101=65319:0 Key102=65314:0 Key103=0:0 Key104=65421:13 Key105=65508:0 Key106=65455:47 Key107=65377:0 Key108=65027:0 Key109=65290:10 Key110=65360:0 Key111=65362:0 Key112=65365:0 Key113=65361:0 Key114=65363:0 Key115=65367:0 Key116=65364:0 Key117=65366:0 Key118=65379:0 Key119=65535:127 Key120=0:0 Key121=269025042:0 Key122=269025041:0 Key123=269025043:0 Key124=269025066:0 Key125=65469:61 Key126=177:177 Key127=65299:0 Key128=269025098:0 Key129=65454:46 Key130=65329:0 Key131=65332:0 Key132=0:0 Key133=65515:0 Key134=65516:0 Key135=65383:0 Key136=65385:0 Key137=65382:0 [capslock] Key8=0:0 Key9=65307:27 Key10=49:49 Key11=50:50 Key12=51:51 Key13=52:52 Key14=53:53 Key15=54:54 Key16=55:55 Key17=56:56 Key18=57:57 Key19=48:48 Key20=45:45 Key21=61:61 Key22=65288:8 Key23=65289:9 Key24=81:81 Key25=87:87 Key26=69:69 Key27=82:82 Key28=84:84 Key29=89:89 Key30=85:85 Key31=73:73 Key32=79:79 Key33=80:80 Key34=65105:180 Key35=91:91 Key36=65293:13 Key37=65507:0 Key38=65:65 Key39=83:83 Key40=68:68 Key41=70:70 Key42=71:71 Key43=72:72 Key44=74:74 Key45=75:75 Key46=76:76 Key47=199:199 Key48=65107:126 Key49=39:39 Key50=65505:0 Key51=93:93 Key52=90:90 Key53=88:88 Key54=67:67 Key55=86:86 Key56=66:66 Key57=78:78 Key58=77:77 Key59=44:44 Key60=46:46 Key61=59:59 Key62=65506:0 Key63=65450:42 Key64=65513:0 Key65=32:32 Key66=65509:0 Key67=65470:0 Key68=65471:0 Key69=65472:0 Key70=65473:0 Key71=65474:0 Key72=65475:0 Key73=65476:0 Key74=65477:0 Key75=65478:0 Key76=65479:0 Key77=65407:0 Key78=65300:0 Key79=65429:0 Key80=65431:0 Key81=65434:0 Key82=65453:45 Key83=65430:0 Key84=65437:0 Key85=65432:0 Key86=65451:43 Key87=65436:0 Key88=65433:0 Key89=65435:0 Key90=65438:0 Key91=65439:0 Key92=65027:0 Key93=0:0 Key94=92:92 Key95=65480:0 Key96=65481:0 Key97=47:47 Key98=65318:0 Key99=65317:0 Key100=65315:0 Key101=65319:0 Key102=65314:0 Key103=0:0 Key104=65421:13 Key105=65508:0 Key106=65455:47 Key107=65377:0 Key108=65027:0 Key109=65290:10 Key110=65360:0 Key111=65362:0 Key112=65365:0 Key113=65361:0 Key114=65363:0 Key115=65367:0 Key116=65364:0 Key117=65366:0 Key118=65379:0 Key119=65535:127 Key120=0:0 Key121=269025042:0 Key122=269025041:0 Key123=269025043:0 Key124=269025066:0 Key125=65469:61 Key126=177:177 Key127=65299:0 Key128=269025098:0 Key129=65454:46 Key130=65329:0 Key131=65332:0 Key132=0:0 Key133=65515:0 Key134=65516:0 Key135=65383:0 Key136=65385:0 Key137=65382:0 [shiftcapslock] Key8=0:0 Key9=65307:27 Key10=33:33 Key11=64:64 Key12=35:35 Key13=36:36 Key14=37:37 Key15=65111:168 Key16=38:38 Key17=42:42 Key18=40:40 Key19=41:41 Key20=95:95 Key21=43:43 Key22=65288:8 Key23=65056:0 Key24=113:113 Key25=119:119 Key26=101:101 Key27=114:114 Key28=116:116 Key29=121:121 Key30=117:117 Key31=105:105 Key32=111:111 Key33=112:112 Key34=65104:96 Key35=123:123 Key36=65293:13 Key37=65507:0 Key38=97:97 Key39=115:115 Key40=100:100 Key41=102:102 Key42=103:103 Key43=104:104 Key44=106:106 Key45=107:107 Key46=108:108 Key47=231:231 Key48=65106:94 Key49=34:34 Key50=65505:0 Key51=125:125 Key52=122:122 Key53=120:120 Key54=99:99 Key55=118:118 Key56=98:98 Key57=110:110 Key58=109:109 Key59=60:60 Key60=62:62 Key61=58:58 Key62=65506:0 Key63=65450:42 Key64=65511:0 Key65=32:32 Key66=65509:0 Key67=65470:0 Key68=65471:0 Key69=65472:0 Key70=65473:0 Key71=65474:0 Key72=65475:0 Key73=65476:0 Key74=65477:0 Key75=65478:0 Key76=65479:0 Key77=65407:0 Key78=65300:0 Key79=65463:55 Key80=65464:56 Key81=65465:57 Key82=65453:45 Key83=65460:52 Key84=65461:53 Key85=65462:54 Key86=65451:43 Key87=65457:49 Key88=65458:50 Key89=65459:51 Key90=65456:48 Key91=65452:44 Key92=65027:0 Key93=0:0 Key94=124:124 Key95=65480:0 Key96=65481:0 Key97=63:63 Key98=65318:0 Key99=65317:0 Key100=65315:0 Key101=65319:0 Key102=65314:0 Key103=0:0 Key104=65421:13 Key105=65508:0 Key106=65455:47 Key107=65377:0 Key108=65027:0 Key109=65290:10 Key110=65360:0 Key111=65362:0 Key112=65365:0 Key113=65361:0 Key114=65363:0 Key115=65367:0 Key116=65364:0 Key117=65366:0 Key118=65379:0 Key119=65535:127 Key120=0:0 Key121=269025042:0 Key122=269025041:0 Key123=269025043:0 Key124=269025066:0 Key125=65469:61 Key126=177:177 Key127=65299:0 Key128=269025098:0 Key129=65454:46 Key130=65329:0 Key131=65332:0 Key132=0:0 Key133=65515:0 Key134=65516:0 Key135=65383:0 Key136=65385:0 Key137=65382:0 xrdp-0.6.0/instfiles/km-0419.ini000066400000000000000000000217211203155130500161730ustar00rootroot00000000000000[noshift] Key8=0:0 Key9=65307:27 Key10=49:49 Key11=50:50 Key12=51:51 Key13=52:52 Key14=53:53 Key15=54:54 Key16=55:55 Key17=56:56 Key18=57:57 Key19=48:48 Key20=45:45 Key21=61:61 Key22=65288:8 Key23=65289:9 Key24=1738:1081 Key25=1731:1094 Key26=1749:1091 Key27=1739:1082 Key28=1733:1077 Key29=1742:1085 Key30=1735:1075 Key31=1755:1096 Key32=1757:1097 Key33=1754:1079 Key34=1736:1093 Key35=1759:1098 Key36=65293:13 Key37=65507:0 Key38=1734:1092 Key39=1753:1099 Key40=1751:1074 Key41=1729:1072 Key42=1744:1087 Key43=1746:1088 Key44=1743:1086 Key45=1740:1083 Key46=1732:1076 Key47=1750:1078 Key48=1756:1101 Key49=1699:1105 Key50=65505:0 Key51=92:92 Key52=1745:1103 Key53=1758:1095 Key54=1747:1089 Key55=1741:1084 Key56=1737:1080 Key57=1748:1090 Key58=1752:1100 Key59=1730:1073 Key60=1728:1102 Key61=47:47 Key62=65506:0 Key63=65450:42 Key64=65513:0 Key65=32:32 Key66=65509:0 Key67=65470:0 Key68=65471:0 Key69=65472:0 Key70=65473:0 Key71=65474:0 Key72=65475:0 Key73=65476:0 Key74=65477:0 Key75=65478:0 Key76=65479:0 Key77=65407:0 Key78=65300:0 Key79=65429:0 Key80=65431:0 Key81=65434:0 Key82=65453:45 Key83=65430:0 Key84=65437:0 Key85=65432:0 Key86=65451:43 Key87=65436:0 Key88=65433:0 Key89=65435:0 Key90=65438:0 Key91=65439:0 Key92=0:0 Key93=65406:0 Key94=47:47 Key95=65480:0 Key96=65481:0 Key97=65360:0 Key98=65362:0 Key99=65365:0 Key100=65361:0 Key101=0:0 Key102=65363:0 Key103=65367:0 Key104=65364:0 Key105=65366:0 Key106=65379:0 Key107=65535:127 Key108=65421:13 Key109=65508:0 Key110=65299:0 Key111=65377:0 Key112=65455:47 Key113=65514:0 Key114=0:0 Key115=65515:0 Key116=65516:0 Key117=65383:0 Key118=0:0 Key119=0:0 Key120=0:0 Key121=0:0 Key122=0:0 Key123=0:0 Key124=65027:0 Key125=0:0 Key126=65469:61 Key127=0:0 Key128=0:0 Key129=0:0 Key130=0:0 Key131=0:0 Key132=0:0 Key133=0:0 Key134=0:0 Key135=0:0 Key136=0:0 Key137=0:0 [shift] Key8=0:0 Key9=65307:27 Key10=33:33 Key11=34:34 Key12=35:35 Key13=42:42 Key14=58:58 Key15=44:44 Key16=46:46 Key17=59:59 Key18=40:40 Key19=41:41 Key20=95:95 Key21=43:43 Key22=65288:8 Key23=65056:0 Key24=1770:1049 Key25=1763:1062 Key26=1781:1059 Key27=1771:1050 Key28=1765:1045 Key29=1774:1053 Key30=1767:1043 Key31=1787:1064 Key32=1789:1065 Key33=1786:1047 Key34=1768:1061 Key35=1791:1066 Key36=65293:13 Key37=65507:0 Key38=1766:1060 Key39=1785:1067 Key40=1783:1042 Key41=1761:1040 Key42=1776:1055 Key43=1778:1056 Key44=1775:1054 Key45=1772:1051 Key46=1764:1044 Key47=1782:1046 Key48=1788:1069 Key49=1715:1025 Key50=65505:0 Key51=124:124 Key52=1777:1071 Key53=1790:1063 Key54=1779:1057 Key55=1773:1052 Key56=1769:1048 Key57=1780:1058 Key58=1784:1068 Key59=1762:1041 Key60=1760:1070 Key61=63:63 Key62=65506:0 Key63=65450:42 Key64=65511:0 Key65=32:32 Key66=65509:0 Key67=65470:0 Key68=65471:0 Key69=65472:0 Key70=65473:0 Key71=65474:0 Key72=65475:0 Key73=65476:0 Key74=65477:0 Key75=65478:0 Key76=65479:0 Key77=65273:0 Key78=65300:0 Key79=65463:55 Key80=65464:56 Key81=65465:57 Key82=65453:45 Key83=65460:52 Key84=65461:53 Key85=65462:54 Key86=65451:43 Key87=65457:49 Key88=65458:50 Key89=65459:51 Key90=65456:48 Key91=65452:44 Key92=0:0 Key93=65406:0 Key94=124:124 Key95=65480:0 Key96=65481:0 Key97=65360:0 Key98=65362:0 Key99=65365:0 Key100=65361:0 Key101=0:0 Key102=65363:0 Key103=65367:0 Key104=65364:0 Key105=65366:0 Key106=65379:0 Key107=65535:127 Key108=65421:13 Key109=65508:0 Key110=65299:0 Key111=65377:0 Key112=65455:47 Key113=65512:0 Key114=0:0 Key115=65515:0 Key116=65516:0 Key117=65383:0 Key118=0:0 Key119=0:0 Key120=0:0 Key121=0:0 Key122=0:0 Key123=0:0 Key124=65027:0 Key125=65513:0 Key126=65469:61 Key127=65515:0 Key128=65517:0 Key129=0:0 Key130=0:0 Key131=0:0 Key132=0:0 Key133=0:0 Key134=0:0 Key135=0:0 Key136=0:0 Key137=0:0 [altgr] Key8=0:0 Key9=65307:27 Key10=49:49 Key11=50:50 Key12=51:51 Key13=52:52 Key14=53:53 Key15=54:54 Key16=55:55 Key17=56:56 Key18=57:57 Key19=48:48 Key20=45:45 Key21=61:61 Key22=65288:8 Key23=65289:9 Key24=1738:1081 Key25=1731:1094 Key26=1749:1091 Key27=1739:1082 Key28=1733:1077 Key29=1742:1085 Key30=1735:1075 Key31=1755:1096 Key32=1757:1097 Key33=1754:1079 Key34=1736:1093 Key35=1759:1098 Key36=65293:13 Key37=65507:0 Key38=1734:1092 Key39=1753:1099 Key40=1751:1074 Key41=1729:1072 Key42=1744:1087 Key43=1746:1088 Key44=1743:1086 Key45=1740:1083 Key46=1732:1076 Key47=1750:1078 Key48=1756:1101 Key49=1699:1105 Key50=65505:0 Key51=92:92 Key52=1745:1103 Key53=1758:1095 Key54=1747:1089 Key55=1741:1084 Key56=1737:1080 Key57=1748:1090 Key58=1752:1100 Key59=1730:1073 Key60=1728:1102 Key61=47:47 Key62=65506:0 Key63=65450:42 Key64=65513:0 Key65=32:32 Key66=65509:0 Key67=65470:0 Key68=65471:0 Key69=65472:0 Key70=65473:0 Key71=65474:0 Key72=65475:0 Key73=65476:0 Key74=65477:0 Key75=65478:0 Key76=65479:0 Key77=65407:0 Key78=65300:0 Key79=65429:0 Key80=65431:0 Key81=65434:0 Key82=65453:45 Key83=65430:0 Key84=65437:0 Key85=65432:0 Key86=65451:43 Key87=65436:0 Key88=65433:0 Key89=65435:0 Key90=65438:0 Key91=65439:0 Key92=0:0 Key93=65406:0 Key94=124:124 Key95=65480:0 Key96=65481:0 Key97=65360:0 Key98=65362:0 Key99=65365:0 Key100=65361:0 Key101=0:0 Key102=65363:0 Key103=65367:0 Key104=65364:0 Key105=65366:0 Key106=65379:0 Key107=65535:127 Key108=65421:13 Key109=65508:0 Key110=65299:0 Key111=0:0 Key112=65455:47 Key113=65514:0 Key114=0:0 Key115=65515:0 Key116=65516:0 Key117=65383:0 Key118=0:0 Key119=0:0 Key120=0:0 Key121=0:0 Key122=0:0 Key123=0:0 Key124=65027:0 Key125=0:0 Key126=65469:61 Key127=0:0 Key128=0:0 Key129=0:0 Key130=0:0 Key131=0:0 Key132=0:0 Key133=0:0 Key134=0:0 Key135=0:0 Key136=0:0 Key137=0:0 [capslock] Key8=0:0 Key9=65307:27 Key10=49:49 Key11=50:50 Key12=51:51 Key13=52:52 Key14=53:53 Key15=54:54 Key16=55:55 Key17=56:56 Key18=57:57 Key19=48:48 Key20=45:45 Key21=61:61 Key22=65288:8 Key23=65289:9 Key24=1770:1049 Key25=1763:1062 Key26=1781:1059 Key27=1771:1050 Key28=1765:1045 Key29=1774:1053 Key30=1767:1043 Key31=1787:1064 Key32=1789:1065 Key33=1786:1047 Key34=1768:1061 Key35=1791:1066 Key36=65293:13 Key37=65507:0 Key38=1766:1060 Key39=1785:1067 Key40=1783:1042 Key41=1761:1040 Key42=1776:1055 Key43=1778:1056 Key44=1775:1054 Key45=1772:1051 Key46=1764:1044 Key47=1782:1046 Key48=1788:1069 Key49=1715:1025 Key50=65505:0 Key51=92:92 Key52=1777:1071 Key53=1790:1063 Key54=1779:1057 Key55=1773:1052 Key56=1769:1048 Key57=1780:1058 Key58=1784:1068 Key59=1762:1041 Key60=1760:1070 Key61=47:47 Key62=65506:0 Key63=65450:42 Key64=65513:0 Key65=32:32 Key66=65509:0 Key67=65470:0 Key68=65471:0 Key69=65472:0 Key70=65473:0 Key71=65474:0 Key72=65475:0 Key73=65476:0 Key74=65477:0 Key75=65478:0 Key76=65479:0 Key77=65407:0 Key78=65300:0 Key79=65429:0 Key80=65431:0 Key81=65434:0 Key82=65453:45 Key83=65430:0 Key84=65437:0 Key85=65432:0 Key86=65451:43 Key87=65436:0 Key88=65433:0 Key89=65435:0 Key90=65438:0 Key91=65439:0 Key92=0:0 Key93=65406:0 Key94=47:47 Key95=65480:0 Key96=65481:0 Key97=65360:0 Key98=65362:0 Key99=65365:0 Key100=65361:0 Key101=0:0 Key102=65363:0 Key103=65367:0 Key104=65364:0 Key105=65366:0 Key106=65379:0 Key107=65535:127 Key108=65421:13 Key109=65508:0 Key110=65299:0 Key111=65377:0 Key112=65455:47 Key113=65514:0 Key114=0:0 Key115=65515:0 Key116=65516:0 Key117=65383:0 Key118=0:0 Key119=0:0 Key120=0:0 Key121=0:0 Key122=0:0 Key123=0:0 Key124=65027:0 Key125=0:0 Key126=65469:61 Key127=0:0 Key128=0:0 Key129=0:0 Key130=0:0 Key131=0:0 Key132=0:0 Key133=0:0 Key134=0:0 Key135=0:0 Key136=0:0 Key137=0:0 [shiftcapslock] Key8=0:0 Key9=65307:27 Key10=33:33 Key11=34:34 Key12=35:35 Key13=42:42 Key14=58:58 Key15=44:44 Key16=46:46 Key17=59:59 Key18=40:40 Key19=41:41 Key20=95:95 Key21=43:43 Key22=65288:8 Key23=65056:0 Key24=1738:1081 Key25=1731:1094 Key26=1749:1091 Key27=1739:1082 Key28=1733:1077 Key29=1742:1085 Key30=1735:1075 Key31=1755:1096 Key32=1757:1097 Key33=1754:1079 Key34=1736:1093 Key35=1759:1098 Key36=65293:13 Key37=65507:0 Key38=1734:1092 Key39=1753:1099 Key40=1751:1074 Key41=1729:1072 Key42=1744:1087 Key43=1746:1088 Key44=1743:1086 Key45=1740:1083 Key46=1732:1076 Key47=1750:1078 Key48=1756:1101 Key49=1699:1105 Key50=65505:0 Key51=124:124 Key52=1745:1103 Key53=1758:1095 Key54=1747:1089 Key55=1741:1084 Key56=1737:1080 Key57=1748:1090 Key58=1752:1100 Key59=1730:1073 Key60=1728:1102 Key61=63:63 Key62=65506:0 Key63=65450:42 Key64=65511:0 Key65=32:32 Key66=65509:0 Key67=65470:0 Key68=65471:0 Key69=65472:0 Key70=65473:0 Key71=65474:0 Key72=65475:0 Key73=65476:0 Key74=65477:0 Key75=65478:0 Key76=65479:0 Key77=65273:0 Key78=65300:0 Key79=65463:55 Key80=65464:56 Key81=65465:57 Key82=65453:45 Key83=65460:52 Key84=65461:53 Key85=65462:54 Key86=65451:43 Key87=65457:49 Key88=65458:50 Key89=65459:51 Key90=65456:48 Key91=65452:44 Key92=0:0 Key93=65406:0 Key94=124:124 Key95=65480:0 Key96=65481:0 Key97=65360:0 Key98=65362:0 Key99=65365:0 Key100=65361:0 Key101=0:0 Key102=65363:0 Key103=65367:0 Key104=65364:0 Key105=65366:0 Key106=65379:0 Key107=65535:127 Key108=65421:13 Key109=65508:0 Key110=65299:0 Key111=65377:0 Key112=65455:47 Key113=65512:0 Key114=0:0 Key115=65515:0 Key116=65516:0 Key117=65383:0 Key118=0:0 Key119=0:0 Key120=0:0 Key121=0:0 Key122=0:0 Key123=0:0 Key124=65027:0 Key125=65513:0 Key126=65469:61 Key127=65515:0 Key128=65517:0 Key129=0:0 Key130=0:0 Key131=0:0 Key132=0:0 Key133=0:0 Key134=0:0 Key135=0:0 Key136=0:0 Key137=0:0 xrdp-0.6.0/instfiles/km-041d.ini000066400000000000000000000210701203155130500162430ustar00rootroot00000000000000[noshift] Key8=0:0 Key9=65307:27 Key10=49:49 Key11=50:50 Key12=51:51 Key13=52:52 Key14=53:53 Key15=54:54 Key16=55:55 Key17=56:56 Key18=57:57 Key19=48:48 Key20=43:43 Key21=65105:180 Key22=65288:8 Key23=65289:9 Key24=113:113 Key25=119:119 Key26=101:101 Key27=114:114 Key28=116:116 Key29=121:121 Key30=117:117 Key31=105:105 Key32=111:111 Key33=112:112 Key34=229:229 Key35=65111:168 Key36=65293:13 Key37=65507:0 Key38=97:97 Key39=115:115 Key40=100:100 Key41=102:102 Key42=103:103 Key43=104:104 Key44=106:106 Key45=107:107 Key46=108:108 Key47=246:246 Key48=228:228 Key49=167:167 Key50=65505:0 Key51=39:39 Key52=122:122 Key53=120:120 Key54=99:99 Key55=118:118 Key56=98:98 Key57=110:110 Key58=109:109 Key59=44:44 Key60=46:46 Key61=45:45 Key62=65506:0 Key63=65450:42 Key64=65513:0 Key65=32:32 Key66=65509:0 Key67=65470:0 Key68=65471:0 Key69=65472:0 Key70=65473:0 Key71=65474:0 Key72=65475:0 Key73=65476:0 Key74=65477:0 Key75=65478:0 Key76=65479:0 Key77=65407:0 Key78=65300:0 Key79=65429:0 Key80=65431:0 Key81=65434:0 Key82=65453:45 Key83=65430:0 Key84=65437:0 Key85=65432:0 Key86=65451:43 Key87=65436:0 Key88=65433:0 Key89=65435:0 Key90=65438:0 Key91=65439:0 Key92=0:0 Key93=65406:0 Key94=60:60 Key95=65480:0 Key96=65481:0 Key97=65360:0 Key98=65362:0 Key99=65365:0 Key100=65361:0 Key101=0:0 Key102=65363:0 Key103=65367:0 Key104=65364:0 Key105=65366:0 Key106=65379:0 Key107=65535:127 Key108=65421:13 Key109=65508:0 Key110=65299:0 Key111=65377:0 Key112=65455:47 Key113=65027:0 Key114=0:0 Key115=65515:0 Key116=65516:0 Key117=65383:0 Key118=0:0 Key119=0:0 Key120=0:0 Key121=0:0 Key122=0:0 Key123=0:0 Key124=65027:0 Key125=0:0 Key126=65469:61 Key127=0:0 Key128=0:0 Key129=0:0 Key130=0:0 Key131=0:0 Key132=0:0 Key133=0:0 Key134=0:0 Key135=0:0 Key136=0:0 Key137=0:0 [shift] Key8=0:0 Key9=65307:27 Key10=33:33 Key11=34:34 Key12=35:35 Key13=164:164 Key14=37:37 Key15=38:38 Key16=47:47 Key17=40:40 Key18=41:41 Key19=61:61 Key20=63:63 Key21=65104:96 Key22=65288:8 Key23=65056:0 Key24=81:81 Key25=87:87 Key26=69:69 Key27=82:82 Key28=84:84 Key29=89:89 Key30=85:85 Key31=73:73 Key32=79:79 Key33=80:80 Key34=197:197 Key35=65106:94 Key36=65293:13 Key37=65507:0 Key38=65:65 Key39=83:83 Key40=68:68 Key41=70:70 Key42=71:71 Key43=72:72 Key44=74:74 Key45=75:75 Key46=76:76 Key47=214:214 Key48=196:196 Key49=189:189 Key50=65505:0 Key51=42:42 Key52=90:90 Key53=88:88 Key54=67:67 Key55=86:86 Key56=66:66 Key57=78:78 Key58=77:77 Key59=59:59 Key60=58:58 Key61=95:95 Key62=65506:0 Key63=65450:42 Key64=65511:0 Key65=32:32 Key66=65509:0 Key67=65470:0 Key68=65471:0 Key69=65472:0 Key70=65473:0 Key71=65474:0 Key72=65475:0 Key73=65476:0 Key74=65477:0 Key75=65478:0 Key76=65479:0 Key77=65273:0 Key78=65300:0 Key79=65463:55 Key80=65464:56 Key81=65465:57 Key82=65453:45 Key83=65460:52 Key84=65461:53 Key85=65462:54 Key86=65451:43 Key87=65457:49 Key88=65458:50 Key89=65459:51 Key90=65456:48 Key91=65452:44 Key92=0:0 Key93=65406:0 Key94=62:62 Key95=65480:0 Key96=65481:0 Key97=65360:0 Key98=65362:0 Key99=65365:0 Key100=65361:0 Key101=0:0 Key102=65363:0 Key103=65367:0 Key104=65364:0 Key105=65366:0 Key106=65379:0 Key107=65535:127 Key108=65421:13 Key109=65508:0 Key110=65299:0 Key111=65377:0 Key112=65455:47 Key113=65027:0 Key114=0:0 Key115=65515:0 Key116=65516:0 Key117=65383:0 Key118=0:0 Key119=0:0 Key120=0:0 Key121=0:0 Key122=0:0 Key123=0:0 Key124=65027:0 Key125=65513:0 Key126=65469:61 Key127=65515:0 Key128=65517:0 Key129=0:0 Key130=0:0 Key131=0:0 Key132=0:0 Key133=0:0 Key134=0:0 Key135=0:0 Key136=0:0 Key137=0:0 [altgr] Key8=0:0 Key9=65307:27 Key10=161:161 Key11=64:64 Key12=163:163 Key13=36:36 Key14=8364:8364 Key15=165:165 Key16=123:123 Key17=91:91 Key18=93:93 Key19=125:125 Key20=92:92 Key21=177:177 Key22=65288:8 Key23=65289:9 Key24=64:64 Key25=435:322 Key26=8364:8364 Key27=174:174 Key28=254:254 Key29=2299:8592 Key30=2302:8595 Key31=2301:8594 Key32=5053:339 Key33=254:254 Key34=65111:168 Key35=65107:126 Key36=65293:13 Key37=65507:0 Key38=170:170 Key39=223:223 Key40=240:240 Key41=496:273 Key42=959:331 Key43=689:295 Key44=106:106 Key45=930:312 Key46=435:322 Key47=248:248 Key48=230:230 Key49=182:182 Key50=65505:0 Key51=180:180 Key52=171:171 Key53=187:187 Key54=169:169 Key55=2770:8220 Key56=2771:8221 Key57=110:110 Key58=181:181 Key59=65115:184 Key60=183:183 Key61=65120:0 Key62=65506:0 Key63=65450:42 Key64=65513:0 Key65=32:32 Key66=65509:0 Key67=65470:0 Key68=65471:0 Key69=65472:0 Key70=65473:0 Key71=65474:0 Key72=65475:0 Key73=65476:0 Key74=65477:0 Key75=65478:0 Key76=65479:0 Key77=65407:0 Key78=65300:0 Key79=65429:0 Key80=65431:0 Key81=65434:0 Key82=65453:45 Key83=65430:0 Key84=65437:0 Key85=65432:0 Key86=65451:43 Key87=65436:0 Key88=65433:0 Key89=65435:0 Key90=65438:0 Key91=65439:0 Key92=0:0 Key93=65406:0 Key94=124:124 Key95=65480:0 Key96=65481:0 Key97=65360:0 Key98=65362:0 Key99=65365:0 Key100=65361:0 Key101=0:0 Key102=65363:0 Key103=65367:0 Key104=65364:0 Key105=65366:0 Key106=65379:0 Key107=65535:127 Key108=65421:13 Key109=65508:0 Key110=65299:0 Key111=0:0 Key112=65455:47 Key113=65027:0 Key114=0:0 Key115=65515:0 Key116=65516:0 Key117=65383:0 Key118=0:0 Key119=0:0 Key120=0:0 Key121=0:0 Key122=0:0 Key123=0:0 Key124=65027:0 Key125=0:0 Key126=65469:61 Key127=0:0 Key128=0:0 Key129=0:0 Key130=0:0 Key131=0:0 Key132=0:0 Key133=0:0 Key134=0:0 Key135=0:0 Key136=0:0 Key137=0:0 [capslock] Key8=0:0 Key9=65307:27 Key10=49:49 Key11=50:50 Key12=51:51 Key13=52:52 Key14=53:53 Key15=54:54 Key16=55:55 Key17=56:56 Key18=57:57 Key19=48:48 Key20=43:43 Key21=65105:180 Key22=65288:8 Key23=65289:9 Key24=81:81 Key25=87:87 Key26=69:69 Key27=82:82 Key28=84:84 Key29=89:89 Key30=85:85 Key31=73:73 Key32=79:79 Key33=80:80 Key34=197:197 Key35=65111:168 Key36=65293:13 Key37=65507:0 Key38=65:65 Key39=83:83 Key40=68:68 Key41=70:70 Key42=71:71 Key43=72:72 Key44=74:74 Key45=75:75 Key46=76:76 Key47=214:214 Key48=196:196 Key49=167:167 Key50=65505:0 Key51=39:39 Key52=90:90 Key53=88:88 Key54=67:67 Key55=86:86 Key56=66:66 Key57=78:78 Key58=77:77 Key59=44:44 Key60=46:46 Key61=45:45 Key62=65506:0 Key63=65450:42 Key64=65513:0 Key65=32:32 Key66=65509:0 Key67=65470:0 Key68=65471:0 Key69=65472:0 Key70=65473:0 Key71=65474:0 Key72=65475:0 Key73=65476:0 Key74=65477:0 Key75=65478:0 Key76=65479:0 Key77=65407:0 Key78=65300:0 Key79=65429:0 Key80=65431:0 Key81=65434:0 Key82=65453:45 Key83=65430:0 Key84=65437:0 Key85=65432:0 Key86=65451:43 Key87=65436:0 Key88=65433:0 Key89=65435:0 Key90=65438:0 Key91=65439:0 Key92=0:0 Key93=65406:0 Key94=60:60 Key95=65480:0 Key96=65481:0 Key97=65360:0 Key98=65362:0 Key99=65365:0 Key100=65361:0 Key101=0:0 Key102=65363:0 Key103=65367:0 Key104=65364:0 Key105=65366:0 Key106=65379:0 Key107=65535:127 Key108=65421:13 Key109=65508:0 Key110=65299:0 Key111=65377:0 Key112=65455:47 Key113=65027:0 Key114=0:0 Key115=65515:0 Key116=65516:0 Key117=65383:0 Key118=0:0 Key119=0:0 Key120=0:0 Key121=0:0 Key122=0:0 Key123=0:0 Key124=65027:0 Key125=0:0 Key126=65469:61 Key127=0:0 Key128=0:0 Key129=0:0 Key130=0:0 Key131=0:0 Key132=0:0 Key133=0:0 Key134=0:0 Key135=0:0 Key136=0:0 Key137=0:0 [shiftcapslock] Key8=0:0 Key9=65307:27 Key10=33:33 Key11=34:34 Key12=35:35 Key13=164:164 Key14=37:37 Key15=38:38 Key16=47:47 Key17=40:40 Key18=41:41 Key19=61:61 Key20=63:63 Key21=65104:96 Key22=65288:8 Key23=65056:0 Key24=113:113 Key25=119:119 Key26=101:101 Key27=114:114 Key28=116:116 Key29=121:121 Key30=117:117 Key31=105:105 Key32=111:111 Key33=112:112 Key34=229:229 Key35=65106:94 Key36=65293:13 Key37=65507:0 Key38=97:97 Key39=115:115 Key40=100:100 Key41=102:102 Key42=103:103 Key43=104:104 Key44=106:106 Key45=107:107 Key46=108:108 Key47=246:246 Key48=228:228 Key49=189:189 Key50=65505:0 Key51=42:42 Key52=122:122 Key53=120:120 Key54=99:99 Key55=118:118 Key56=98:98 Key57=110:110 Key58=109:109 Key59=59:59 Key60=58:58 Key61=95:95 Key62=65506:0 Key63=65450:42 Key64=65511:0 Key65=32:32 Key66=65509:0 Key67=65470:0 Key68=65471:0 Key69=65472:0 Key70=65473:0 Key71=65474:0 Key72=65475:0 Key73=65476:0 Key74=65477:0 Key75=65478:0 Key76=65479:0 Key77=65273:0 Key78=65300:0 Key79=65463:55 Key80=65464:56 Key81=65465:57 Key82=65453:45 Key83=65460:52 Key84=65461:53 Key85=65462:54 Key86=65451:43 Key87=65457:49 Key88=65458:50 Key89=65459:51 Key90=65456:48 Key91=65452:44 Key92=0:0 Key93=65406:0 Key94=62:62 Key95=65480:0 Key96=65481:0 Key97=65360:0 Key98=65362:0 Key99=65365:0 Key100=65361:0 Key101=0:0 Key102=65363:0 Key103=65367:0 Key104=65364:0 Key105=65366:0 Key106=65379:0 Key107=65535:127 Key108=65421:13 Key109=65508:0 Key110=65299:0 Key111=65377:0 Key112=65455:47 Key113=65027:0 Key114=0:0 Key115=65515:0 Key116=65516:0 Key117=65383:0 Key118=0:0 Key119=0:0 Key120=0:0 Key121=0:0 Key122=0:0 Key123=0:0 Key124=65027:0 Key125=65513:0 Key126=65469:61 Key127=65515:0 Key128=65517:0 Key129=0:0 Key130=0:0 Key131=0:0 Key132=0:0 Key133=0:0 Key134=0:0 Key135=0:0 Key136=0:0 Key137=0:0 xrdp-0.6.0/instfiles/km-0807.ini000066400000000000000000000207621203155130500162000ustar00rootroot00000000000000[noshift] Key8=0:0 Key9=65307:27 Key10=49:49 Key11=50:50 Key12=51:51 Key13=52:52 Key14=53:53 Key15=54:54 Key16=55:55 Key17=56:56 Key18=57:57 Key19=48:48 Key20=39:39 Key21=65106:94 Key22=65288:8 Key23=65289:9 Key24=113:113 Key25=119:119 Key26=101:101 Key27=114:114 Key28=116:116 Key29=122:122 Key30=117:117 Key31=105:105 Key32=111:111 Key33=112:112 Key34=252:252 Key35=65111:168 Key36=65293:13 Key37=65507:0 Key38=97:97 Key39=115:115 Key40=100:100 Key41=102:102 Key42=103:103 Key43=104:104 Key44=106:106 Key45=107:107 Key46=108:108 Key47=246:246 Key48=228:228 Key49=167:167 Key50=65505:0 Key51=36:36 Key52=121:121 Key53=120:120 Key54=99:99 Key55=118:118 Key56=98:98 Key57=110:110 Key58=109:109 Key59=44:44 Key60=46:46 Key61=45:45 Key62=65506:0 Key63=65450:42 Key64=65513:0 Key65=32:32 Key66=65509:0 Key67=65470:0 Key68=65471:0 Key69=65472:0 Key70=65473:0 Key71=65474:0 Key72=65475:0 Key73=65476:0 Key74=65477:0 Key75=65478:0 Key76=65479:0 Key77=65407:0 Key78=65300:0 Key79=65429:0 Key80=65431:0 Key81=65434:0 Key82=65453:45 Key83=65430:0 Key84=65437:0 Key85=65432:0 Key86=65451:43 Key87=65436:0 Key88=65433:0 Key89=65435:0 Key90=65438:0 Key91=65439:0 Key92=0:0 Key93=65406:0 Key94=60:60 Key95=65480:0 Key96=65481:0 Key97=65360:0 Key98=65362:0 Key99=65365:0 Key100=65361:0 Key101=0:0 Key102=65363:0 Key103=65367:0 Key104=65364:0 Key105=65366:0 Key106=65379:0 Key107=65535:127 Key108=65421:13 Key109=65508:0 Key110=65299:0 Key111=65377:0 Key112=65455:47 Key113=65027:0 Key114=0:0 Key115=0:0 Key116=0:0 Key117=0:0 Key118=0:0 Key119=0:0 Key120=0:0 Key121=0:0 Key122=0:0 Key123=0:0 Key124=65027:0 Key125=0:0 Key126=65469:61 Key127=0:0 Key128=0:0 Key129=0:0 Key130=0:0 Key131=0:0 Key132=0:0 Key133=0:0 Key134=0:0 Key135=0:0 Key136=0:0 Key137=0:0 [shift] Key8=0:0 Key9=65307:27 Key10=43:43 Key11=34:34 Key12=42:42 Key13=231:231 Key14=37:37 Key15=38:38 Key16=47:47 Key17=40:40 Key18=41:41 Key19=61:61 Key20=63:63 Key21=65104:96 Key22=65288:8 Key23=65056:0 Key24=81:81 Key25=87:87 Key26=69:69 Key27=82:82 Key28=84:84 Key29=90:90 Key30=85:85 Key31=73:73 Key32=79:79 Key33=80:80 Key34=232:232 Key35=33:33 Key36=65293:13 Key37=65507:0 Key38=65:65 Key39=83:83 Key40=68:68 Key41=70:70 Key42=71:71 Key43=72:72 Key44=74:74 Key45=75:75 Key46=76:76 Key47=233:233 Key48=224:224 Key49=176:176 Key50=65505:0 Key51=163:163 Key52=89:89 Key53=88:88 Key54=67:67 Key55=86:86 Key56=66:66 Key57=78:78 Key58=77:77 Key59=59:59 Key60=58:58 Key61=95:95 Key62=65506:0 Key63=65450:42 Key64=65511:0 Key65=32:32 Key66=65509:0 Key67=65470:0 Key68=65471:0 Key69=65472:0 Key70=65473:0 Key71=65474:0 Key72=65475:0 Key73=65476:0 Key74=65477:0 Key75=65478:0 Key76=65479:0 Key77=65273:0 Key78=65300:0 Key79=65463:55 Key80=65464:56 Key81=65465:57 Key82=65453:45 Key83=65460:52 Key84=65461:53 Key85=65462:54 Key86=65451:43 Key87=65457:49 Key88=65458:50 Key89=65459:51 Key90=65456:48 Key91=65454:46 Key92=0:0 Key93=65406:0 Key94=62:62 Key95=65480:0 Key96=65481:0 Key97=65360:0 Key98=65362:0 Key99=65365:0 Key100=65361:0 Key101=0:0 Key102=65363:0 Key103=65367:0 Key104=65364:0 Key105=65366:0 Key106=65379:0 Key107=65535:127 Key108=65421:13 Key109=65508:0 Key110=65299:0 Key111=65377:0 Key112=65455:47 Key113=65312:0 Key114=0:0 Key115=0:0 Key116=0:0 Key117=0:0 Key118=0:0 Key119=0:0 Key120=0:0 Key121=0:0 Key122=0:0 Key123=0:0 Key124=65027:0 Key125=65513:0 Key126=65469:61 Key127=65515:0 Key128=65517:0 Key129=0:0 Key130=0:0 Key131=0:0 Key132=0:0 Key133=0:0 Key134=0:0 Key135=0:0 Key136=0:0 Key137=0:0 [altgr] Key8=0:0 Key9=65307:27 Key10=124:124 Key11=64:64 Key12=35:35 Key13=188:188 Key14=189:189 Key15=172:172 Key16=166:166 Key17=162:162 Key18=93:93 Key19=125:125 Key20=65105:180 Key21=65107:126 Key22=65288:8 Key23=65289:9 Key24=64:64 Key25=435:322 Key26=8364:8364 Key27=182:182 Key28=956:359 Key29=2299:8592 Key30=2302:8595 Key31=2301:8594 Key32=248:248 Key33=254:254 Key34=91:91 Key35=93:93 Key36=65293:13 Key37=65507:0 Key38=230:230 Key39=223:223 Key40=240:240 Key41=496:273 Key42=959:331 Key43=689:295 Key44=106:106 Key45=930:312 Key46=435:322 Key47=65105:180 Key48=123:123 Key49=172:172 Key50=65505:0 Key51=125:125 Key52=171:171 Key53=187:187 Key54=162:162 Key55=2770:8220 Key56=2771:8221 Key57=110:110 Key58=181:181 Key59=2211:0 Key60=183:183 Key61=65120:0 Key62=65506:0 Key63=65450:42 Key64=65513:0 Key65=32:32 Key66=65509:0 Key67=65470:0 Key68=65471:0 Key69=65472:0 Key70=65473:0 Key71=65474:0 Key72=65475:0 Key73=65476:0 Key74=65477:0 Key75=65478:0 Key76=65479:0 Key77=65407:0 Key78=65300:0 Key79=65429:0 Key80=65431:0 Key81=65434:0 Key82=65453:45 Key83=65430:0 Key84=65437:0 Key85=65432:0 Key86=65451:43 Key87=65436:0 Key88=65433:0 Key89=65435:0 Key90=65438:0 Key91=65439:0 Key92=0:0 Key93=65406:0 Key94=92:92 Key95=65480:0 Key96=65481:0 Key97=65360:0 Key98=65362:0 Key99=65365:0 Key100=65361:0 Key101=0:0 Key102=65363:0 Key103=65367:0 Key104=65364:0 Key105=65366:0 Key106=65379:0 Key107=65535:127 Key108=65421:13 Key109=65508:0 Key110=65299:0 Key111=0:0 Key112=65455:47 Key113=65027:0 Key114=0:0 Key115=0:0 Key116=0:0 Key117=0:0 Key118=0:0 Key119=0:0 Key120=0:0 Key121=0:0 Key122=0:0 Key123=0:0 Key124=65027:0 Key125=0:0 Key126=65469:61 Key127=0:0 Key128=0:0 Key129=0:0 Key130=0:0 Key131=0:0 Key132=0:0 Key133=0:0 Key134=0:0 Key135=0:0 Key136=0:0 Key137=0:0 [capslock] Key8=0:0 Key9=65307:27 Key10=49:49 Key11=50:50 Key12=51:51 Key13=52:52 Key14=53:53 Key15=54:54 Key16=55:55 Key17=56:56 Key18=57:57 Key19=48:48 Key20=39:39 Key21=65106:94 Key22=65288:8 Key23=65289:9 Key24=81:81 Key25=87:87 Key26=69:69 Key27=82:82 Key28=84:84 Key29=90:90 Key30=85:85 Key31=73:73 Key32=79:79 Key33=80:80 Key34=220:220 Key35=65111:168 Key36=65293:13 Key37=65507:0 Key38=65:65 Key39=83:83 Key40=68:68 Key41=70:70 Key42=71:71 Key43=72:72 Key44=74:74 Key45=75:75 Key46=76:76 Key47=214:214 Key48=196:196 Key49=167:167 Key50=65505:0 Key51=36:36 Key52=89:89 Key53=88:88 Key54=67:67 Key55=86:86 Key56=66:66 Key57=78:78 Key58=77:77 Key59=44:44 Key60=46:46 Key61=45:45 Key62=65506:0 Key63=65450:42 Key64=65513:0 Key65=32:32 Key66=65509:0 Key67=65470:0 Key68=65471:0 Key69=65472:0 Key70=65473:0 Key71=65474:0 Key72=65475:0 Key73=65476:0 Key74=65477:0 Key75=65478:0 Key76=65479:0 Key77=65407:0 Key78=65300:0 Key79=65429:0 Key80=65431:0 Key81=65434:0 Key82=65453:45 Key83=65430:0 Key84=65437:0 Key85=65432:0 Key86=65451:43 Key87=65436:0 Key88=65433:0 Key89=65435:0 Key90=65438:0 Key91=65439:0 Key92=0:0 Key93=65406:0 Key94=60:60 Key95=65480:0 Key96=65481:0 Key97=65360:0 Key98=65362:0 Key99=65365:0 Key100=65361:0 Key101=0:0 Key102=65363:0 Key103=65367:0 Key104=65364:0 Key105=65366:0 Key106=65379:0 Key107=65535:127 Key108=65421:13 Key109=65508:0 Key110=65299:0 Key111=65377:0 Key112=65455:47 Key113=65027:0 Key114=0:0 Key115=0:0 Key116=0:0 Key117=0:0 Key118=0:0 Key119=0:0 Key120=0:0 Key121=0:0 Key122=0:0 Key123=0:0 Key124=65027:0 Key125=0:0 Key126=65469:61 Key127=0:0 Key128=0:0 Key129=0:0 Key130=0:0 Key131=0:0 Key132=0:0 Key133=0:0 Key134=0:0 Key135=0:0 Key136=0:0 Key137=0:0 [shiftcapslock] Key8=0:0 Key9=65307:27 Key10=43:43 Key11=34:34 Key12=42:42 Key13=199:199 Key14=37:37 Key15=38:38 Key16=47:47 Key17=40:40 Key18=41:41 Key19=61:61 Key20=63:63 Key21=65104:96 Key22=65288:8 Key23=65056:0 Key24=113:113 Key25=119:119 Key26=101:101 Key27=114:114 Key28=116:116 Key29=122:122 Key30=117:117 Key31=105:105 Key32=111:111 Key33=112:112 Key34=200:200 Key35=33:33 Key36=65293:13 Key37=65507:0 Key38=97:97 Key39=115:115 Key40=100:100 Key41=102:102 Key42=103:103 Key43=104:104 Key44=106:106 Key45=107:107 Key46=108:108 Key47=201:201 Key48=192:192 Key49=176:176 Key50=65505:0 Key51=163:163 Key52=121:121 Key53=120:120 Key54=99:99 Key55=118:118 Key56=98:98 Key57=110:110 Key58=109:109 Key59=59:59 Key60=58:58 Key61=95:95 Key62=65506:0 Key63=65450:42 Key64=65511:0 Key65=32:32 Key66=65509:0 Key67=65470:0 Key68=65471:0 Key69=65472:0 Key70=65473:0 Key71=65474:0 Key72=65475:0 Key73=65476:0 Key74=65477:0 Key75=65478:0 Key76=65479:0 Key77=65273:0 Key78=65300:0 Key79=65463:55 Key80=65464:56 Key81=65465:57 Key82=65453:45 Key83=65460:52 Key84=65461:53 Key85=65462:54 Key86=65451:43 Key87=65457:49 Key88=65458:50 Key89=65459:51 Key90=65456:48 Key91=65454:46 Key92=0:0 Key93=65406:0 Key94=62:62 Key95=65480:0 Key96=65481:0 Key97=65360:0 Key98=65362:0 Key99=65365:0 Key100=65361:0 Key101=0:0 Key102=65363:0 Key103=65367:0 Key104=65364:0 Key105=65366:0 Key106=65379:0 Key107=65535:127 Key108=65421:13 Key109=65508:0 Key110=65299:0 Key111=65377:0 Key112=65455:47 Key113=65312:0 Key114=0:0 Key115=0:0 Key116=0:0 Key117=0:0 Key118=0:0 Key119=0:0 Key120=0:0 Key121=0:0 Key122=0:0 Key123=0:0 Key124=65027:0 Key125=65513:0 Key126=65469:61 Key127=65515:0 Key128=65517:0 Key129=0:0 Key130=0:0 Key131=0:0 Key132=0:0 Key133=0:0 Key134=0:0 Key135=0:0 Key136=0:0 Key137=0:0 xrdp-0.6.0/instfiles/km-080c.ini000066400000000000000000000210601203155130500162440ustar00rootroot00000000000000[noshift] Key8=0:0 Key9=65307:27 Key10=38:38 Key11=233:233 Key12=34:34 Key13=39:39 Key14=40:40 Key15=167:167 Key16=232:232 Key17=33:33 Key18=231:231 Key19=224:224 Key20=41:41 Key21=45:45 Key22=65288:8 Key23=65289:9 Key24=97:97 Key25=122:122 Key26=101:101 Key27=114:114 Key28=116:116 Key29=121:121 Key30=117:117 Key31=105:105 Key32=111:111 Key33=112:112 Key34=65106:94 Key35=36:36 Key36=65293:13 Key37=65507:0 Key38=113:113 Key39=115:115 Key40=100:100 Key41=102:102 Key42=103:103 Key43=104:104 Key44=106:106 Key45=107:107 Key46=108:108 Key47=109:109 Key48=249:249 Key49=178:178 Key50=65505:0 Key51=181:181 Key52=119:119 Key53=120:120 Key54=99:99 Key55=118:118 Key56=98:98 Key57=110:110 Key58=44:44 Key59=59:59 Key60=58:58 Key61=61:61 Key62=65506:0 Key63=65450:42 Key64=65513:0 Key65=32:32 Key66=65509:0 Key67=65470:0 Key68=65471:0 Key69=65472:0 Key70=65473:0 Key71=65474:0 Key72=65475:0 Key73=65476:0 Key74=65477:0 Key75=65478:0 Key76=65479:0 Key77=65407:0 Key78=65300:0 Key79=65429:0 Key80=65431:0 Key81=65434:0 Key82=65453:45 Key83=65430:0 Key84=65437:0 Key85=65432:0 Key86=65451:43 Key87=65436:0 Key88=65433:0 Key89=65435:0 Key90=65438:0 Key91=65439:0 Key92=0:0 Key93=65406:0 Key94=60:60 Key95=65480:0 Key96=65481:0 Key97=65360:0 Key98=65362:0 Key99=65365:0 Key100=65361:0 Key101=0:0 Key102=65363:0 Key103=65367:0 Key104=65364:0 Key105=65366:0 Key106=65379:0 Key107=65535:127 Key108=65421:13 Key109=65508:0 Key110=65299:0 Key111=65377:0 Key112=65455:47 Key113=65027:0 Key114=0:0 Key115=65515:0 Key116=65516:0 Key117=65383:0 Key118=0:0 Key119=0:0 Key120=0:0 Key121=0:0 Key122=0:0 Key123=0:0 Key124=65027:0 Key125=0:0 Key126=65469:61 Key127=0:0 Key128=0:0 Key129=0:0 Key130=0:0 Key131=0:0 Key132=0:0 Key133=0:0 Key134=0:0 Key135=0:0 Key136=0:0 Key137=0:0 [shift] Key8=0:0 Key9=65307:27 Key10=49:49 Key11=50:50 Key12=51:51 Key13=52:52 Key14=53:53 Key15=54:54 Key16=55:55 Key17=56:56 Key18=57:57 Key19=48:48 Key20=176:176 Key21=95:95 Key22=65288:8 Key23=65056:0 Key24=65:65 Key25=90:90 Key26=69:69 Key27=82:82 Key28=84:84 Key29=89:89 Key30=85:85 Key31=73:73 Key32=79:79 Key33=80:80 Key34=65111:168 Key35=42:42 Key36=65293:13 Key37=65507:0 Key38=81:81 Key39=83:83 Key40=68:68 Key41=70:70 Key42=71:71 Key43=72:72 Key44=74:74 Key45=75:75 Key46=76:76 Key47=77:77 Key48=37:37 Key49=179:179 Key50=65505:0 Key51=163:163 Key52=87:87 Key53=88:88 Key54=67:67 Key55=86:86 Key56=66:66 Key57=78:78 Key58=63:63 Key59=46:46 Key60=47:47 Key61=43:43 Key62=65506:0 Key63=65450:42 Key64=65511:0 Key65=32:32 Key66=65509:0 Key67=65470:0 Key68=65471:0 Key69=65472:0 Key70=65473:0 Key71=65474:0 Key72=65475:0 Key73=65476:0 Key74=65477:0 Key75=65478:0 Key76=65479:0 Key77=65273:0 Key78=65300:0 Key79=65463:55 Key80=65464:56 Key81=65465:57 Key82=65453:45 Key83=65460:52 Key84=65461:53 Key85=65462:54 Key86=65451:43 Key87=65457:49 Key88=65458:50 Key89=65459:51 Key90=65456:48 Key91=65454:46 Key92=0:0 Key93=65406:0 Key94=62:62 Key95=65480:0 Key96=65481:0 Key97=65360:0 Key98=65362:0 Key99=65365:0 Key100=65361:0 Key101=0:0 Key102=65363:0 Key103=65367:0 Key104=65364:0 Key105=65366:0 Key106=65379:0 Key107=65535:127 Key108=65421:13 Key109=65508:0 Key110=65299:0 Key111=65377:0 Key112=65455:47 Key113=65027:0 Key114=0:0 Key115=65515:0 Key116=65516:0 Key117=65383:0 Key118=0:0 Key119=0:0 Key120=0:0 Key121=0:0 Key122=0:0 Key123=0:0 Key124=65027:0 Key125=65513:0 Key126=65469:61 Key127=65515:0 Key128=65517:0 Key129=0:0 Key130=0:0 Key131=0:0 Key132=0:0 Key133=0:0 Key134=0:0 Key135=0:0 Key136=0:0 Key137=0:0 [altgr] Key8=0:0 Key9=65307:27 Key10=124:124 Key11=64:64 Key12=35:35 Key13=188:188 Key14=189:189 Key15=94:94 Key16=123:123 Key17=91:91 Key18=123:123 Key19=125:125 Key20=92:92 Key21=65115:184 Key22=65288:8 Key23=65289:9 Key24=64:64 Key25=435:322 Key26=8364:8364 Key27=182:182 Key28=956:359 Key29=2299:8592 Key30=2302:8595 Key31=2301:8594 Key32=5053:339 Key33=254:254 Key34=91:91 Key35=93:93 Key36=65293:13 Key37=65507:0 Key38=230:230 Key39=223:223 Key40=240:240 Key41=496:273 Key42=959:331 Key43=689:295 Key44=106:106 Key45=930:312 Key46=435:322 Key47=65105:180 Key48=65105:180 Key49=172:172 Key50=65505:0 Key51=65104:96 Key52=171:171 Key53=187:187 Key54=162:162 Key55=2770:8220 Key56=2771:8221 Key57=110:110 Key58=65115:184 Key59=2211:0 Key60=183:183 Key61=65107:126 Key62=65506:0 Key63=65450:42 Key64=65513:0 Key65=32:32 Key66=65509:0 Key67=65470:0 Key68=65471:0 Key69=65472:0 Key70=65473:0 Key71=65474:0 Key72=65475:0 Key73=65476:0 Key74=65477:0 Key75=65478:0 Key76=65479:0 Key77=65407:0 Key78=65300:0 Key79=65429:0 Key80=65431:0 Key81=65434:0 Key82=65453:45 Key83=65430:0 Key84=65437:0 Key85=65432:0 Key86=65451:43 Key87=65436:0 Key88=65433:0 Key89=65435:0 Key90=65438:0 Key91=65439:0 Key92=0:0 Key93=65406:0 Key94=92:92 Key95=65480:0 Key96=65481:0 Key97=65360:0 Key98=65362:0 Key99=65365:0 Key100=65361:0 Key101=0:0 Key102=65363:0 Key103=65367:0 Key104=65364:0 Key105=65366:0 Key106=65379:0 Key107=65535:127 Key108=65421:13 Key109=65508:0 Key110=65299:0 Key111=65377:0 Key112=65455:47 Key113=65027:0 Key114=0:0 Key115=65515:0 Key116=65516:0 Key117=65383:0 Key118=0:0 Key119=0:0 Key120=0:0 Key121=0:0 Key122=0:0 Key123=0:0 Key124=65027:0 Key125=0:0 Key126=65469:61 Key127=0:0 Key128=0:0 Key129=0:0 Key130=0:0 Key131=0:0 Key132=0:0 Key133=0:0 Key134=0:0 Key135=0:0 Key136=0:0 Key137=0:0 [capslock] Key8=0:0 Key9=65307:27 Key10=38:38 Key11=201:201 Key12=34:34 Key13=39:39 Key14=40:40 Key15=167:167 Key16=200:200 Key17=33:33 Key18=199:199 Key19=192:192 Key20=41:41 Key21=45:45 Key22=65288:8 Key23=65289:9 Key24=65:65 Key25=90:90 Key26=69:69 Key27=82:82 Key28=84:84 Key29=89:89 Key30=85:85 Key31=73:73 Key32=79:79 Key33=80:80 Key34=65106:94 Key35=36:36 Key36=65293:13 Key37=65507:0 Key38=81:81 Key39=83:83 Key40=68:68 Key41=70:70 Key42=71:71 Key43=72:72 Key44=74:74 Key45=75:75 Key46=76:76 Key47=77:77 Key48=217:217 Key49=178:178 Key50=65505:0 Key51=924:0 Key52=87:87 Key53=88:88 Key54=67:67 Key55=86:86 Key56=66:66 Key57=78:78 Key58=44:44 Key59=59:59 Key60=58:58 Key61=61:61 Key62=65506:0 Key63=65450:42 Key64=65513:0 Key65=32:32 Key66=65509:0 Key67=65470:0 Key68=65471:0 Key69=65472:0 Key70=65473:0 Key71=65474:0 Key72=65475:0 Key73=65476:0 Key74=65477:0 Key75=65478:0 Key76=65479:0 Key77=65407:0 Key78=65300:0 Key79=65429:0 Key80=65431:0 Key81=65434:0 Key82=65453:45 Key83=65430:0 Key84=65437:0 Key85=65432:0 Key86=65451:43 Key87=65436:0 Key88=65433:0 Key89=65435:0 Key90=65438:0 Key91=65439:0 Key92=0:0 Key93=65406:0 Key94=60:60 Key95=65480:0 Key96=65481:0 Key97=65360:0 Key98=65362:0 Key99=65365:0 Key100=65361:0 Key101=0:0 Key102=65363:0 Key103=65367:0 Key104=65364:0 Key105=65366:0 Key106=65379:0 Key107=65535:127 Key108=65421:13 Key109=65508:0 Key110=65299:0 Key111=65377:0 Key112=65455:47 Key113=65027:0 Key114=0:0 Key115=65515:0 Key116=65516:0 Key117=65383:0 Key118=0:0 Key119=0:0 Key120=0:0 Key121=0:0 Key122=0:0 Key123=0:0 Key124=65027:0 Key125=0:0 Key126=65469:61 Key127=0:0 Key128=0:0 Key129=0:0 Key130=0:0 Key131=0:0 Key132=0:0 Key133=0:0 Key134=0:0 Key135=0:0 Key136=0:0 Key137=0:0 [shiftcapslock] Key8=0:0 Key9=65307:27 Key10=49:49 Key11=50:50 Key12=51:51 Key13=52:52 Key14=53:53 Key15=54:54 Key16=55:55 Key17=56:56 Key18=57:57 Key19=48:48 Key20=176:176 Key21=95:95 Key22=65288:8 Key23=65056:0 Key24=97:97 Key25=122:122 Key26=101:101 Key27=114:114 Key28=116:116 Key29=121:121 Key30=117:117 Key31=105:105 Key32=111:111 Key33=112:112 Key34=65111:168 Key35=42:42 Key36=65293:13 Key37=65507:0 Key38=113:113 Key39=115:115 Key40=100:100 Key41=102:102 Key42=103:103 Key43=104:104 Key44=106:106 Key45=107:107 Key46=108:108 Key47=109:109 Key48=37:37 Key49=179:179 Key50=65505:0 Key51=163:163 Key52=119:119 Key53=120:120 Key54=99:99 Key55=118:118 Key56=98:98 Key57=110:110 Key58=63:63 Key59=46:46 Key60=47:47 Key61=43:43 Key62=65506:0 Key63=65450:42 Key64=65511:0 Key65=32:32 Key66=65509:0 Key67=65470:0 Key68=65471:0 Key69=65472:0 Key70=65473:0 Key71=65474:0 Key72=65475:0 Key73=65476:0 Key74=65477:0 Key75=65478:0 Key76=65479:0 Key77=65273:0 Key78=65300:0 Key79=65463:55 Key80=65464:56 Key81=65465:57 Key82=65453:45 Key83=65460:52 Key84=65461:53 Key85=65462:54 Key86=65451:43 Key87=65457:49 Key88=65458:50 Key89=65459:51 Key90=65456:48 Key91=65454:46 Key92=0:0 Key93=65406:0 Key94=62:62 Key95=65480:0 Key96=65481:0 Key97=65360:0 Key98=65362:0 Key99=65365:0 Key100=65361:0 Key101=0:0 Key102=65363:0 Key103=65367:0 Key104=65364:0 Key105=65366:0 Key106=65379:0 Key107=65535:127 Key108=65421:13 Key109=65508:0 Key110=65299:0 Key111=65377:0 Key112=65455:47 Key113=65027:0 Key114=0:0 Key115=65515:0 Key116=65516:0 Key117=65383:0 Key118=0:0 Key119=0:0 Key120=0:0 Key121=0:0 Key122=0:0 Key123=0:0 Key124=65027:0 Key125=65513:0 Key126=65469:61 Key127=65515:0 Key128=65517:0 Key129=0:0 Key130=0:0 Key131=0:0 Key132=0:0 Key133=0:0 Key134=0:0 Key135=0:0 Key136=0:0 Key137=0:0 xrdp-0.6.0/instfiles/km-0813.ini000066400000000000000000000210601203155130500161650ustar00rootroot00000000000000[noshift] Key8=0:0 Key9=65307:27 Key10=38:38 Key11=233:233 Key12=34:34 Key13=39:39 Key14=40:40 Key15=167:167 Key16=232:232 Key17=33:33 Key18=231:231 Key19=224:224 Key20=41:41 Key21=45:45 Key22=65288:8 Key23=65289:9 Key24=97:97 Key25=122:122 Key26=101:101 Key27=114:114 Key28=116:116 Key29=121:121 Key30=117:117 Key31=105:105 Key32=111:111 Key33=112:112 Key34=65106:94 Key35=36:36 Key36=65293:13 Key37=65507:0 Key38=113:113 Key39=115:115 Key40=100:100 Key41=102:102 Key42=103:103 Key43=104:104 Key44=106:106 Key45=107:107 Key46=108:108 Key47=109:109 Key48=249:249 Key49=178:178 Key50=65505:0 Key51=181:181 Key52=119:119 Key53=120:120 Key54=99:99 Key55=118:118 Key56=98:98 Key57=110:110 Key58=44:44 Key59=59:59 Key60=58:58 Key61=61:61 Key62=65506:0 Key63=65450:42 Key64=65513:0 Key65=32:32 Key66=65509:0 Key67=65470:0 Key68=65471:0 Key69=65472:0 Key70=65473:0 Key71=65474:0 Key72=65475:0 Key73=65476:0 Key74=65477:0 Key75=65478:0 Key76=65479:0 Key77=65407:0 Key78=65300:0 Key79=65429:0 Key80=65431:0 Key81=65434:0 Key82=65453:45 Key83=65430:0 Key84=65437:0 Key85=65432:0 Key86=65451:43 Key87=65436:0 Key88=65433:0 Key89=65435:0 Key90=65438:0 Key91=65439:0 Key92=0:0 Key93=65406:0 Key94=60:60 Key95=65480:0 Key96=65481:0 Key97=65360:0 Key98=65362:0 Key99=65365:0 Key100=65361:0 Key101=0:0 Key102=65363:0 Key103=65367:0 Key104=65364:0 Key105=65366:0 Key106=65379:0 Key107=65535:127 Key108=65421:13 Key109=65508:0 Key110=65299:0 Key111=65377:0 Key112=65455:47 Key113=65027:0 Key114=0:0 Key115=65515:0 Key116=65516:0 Key117=65383:0 Key118=0:0 Key119=0:0 Key120=0:0 Key121=0:0 Key122=0:0 Key123=0:0 Key124=65027:0 Key125=0:0 Key126=65469:61 Key127=0:0 Key128=0:0 Key129=0:0 Key130=0:0 Key131=0:0 Key132=0:0 Key133=0:0 Key134=0:0 Key135=0:0 Key136=0:0 Key137=0:0 [shift] Key8=0:0 Key9=65307:27 Key10=49:49 Key11=50:50 Key12=51:51 Key13=52:52 Key14=53:53 Key15=54:54 Key16=55:55 Key17=56:56 Key18=57:57 Key19=48:48 Key20=176:176 Key21=95:95 Key22=65288:8 Key23=65056:0 Key24=65:65 Key25=90:90 Key26=69:69 Key27=82:82 Key28=84:84 Key29=89:89 Key30=85:85 Key31=73:73 Key32=79:79 Key33=80:80 Key34=65111:168 Key35=42:42 Key36=65293:13 Key37=65507:0 Key38=81:81 Key39=83:83 Key40=68:68 Key41=70:70 Key42=71:71 Key43=72:72 Key44=74:74 Key45=75:75 Key46=76:76 Key47=77:77 Key48=37:37 Key49=179:179 Key50=65505:0 Key51=163:163 Key52=87:87 Key53=88:88 Key54=67:67 Key55=86:86 Key56=66:66 Key57=78:78 Key58=63:63 Key59=46:46 Key60=47:47 Key61=43:43 Key62=65506:0 Key63=65450:42 Key64=65511:0 Key65=32:32 Key66=65509:0 Key67=65470:0 Key68=65471:0 Key69=65472:0 Key70=65473:0 Key71=65474:0 Key72=65475:0 Key73=65476:0 Key74=65477:0 Key75=65478:0 Key76=65479:0 Key77=65273:0 Key78=65300:0 Key79=65463:55 Key80=65464:56 Key81=65465:57 Key82=65453:45 Key83=65460:52 Key84=65461:53 Key85=65462:54 Key86=65451:43 Key87=65457:49 Key88=65458:50 Key89=65459:51 Key90=65456:48 Key91=65454:46 Key92=0:0 Key93=65406:0 Key94=62:62 Key95=65480:0 Key96=65481:0 Key97=65360:0 Key98=65362:0 Key99=65365:0 Key100=65361:0 Key101=0:0 Key102=65363:0 Key103=65367:0 Key104=65364:0 Key105=65366:0 Key106=65379:0 Key107=65535:127 Key108=65421:13 Key109=65508:0 Key110=65299:0 Key111=65377:0 Key112=65455:47 Key113=65027:0 Key114=0:0 Key115=65515:0 Key116=65516:0 Key117=65383:0 Key118=0:0 Key119=0:0 Key120=0:0 Key121=0:0 Key122=0:0 Key123=0:0 Key124=65027:0 Key125=65513:0 Key126=65469:61 Key127=65515:0 Key128=65517:0 Key129=0:0 Key130=0:0 Key131=0:0 Key132=0:0 Key133=0:0 Key134=0:0 Key135=0:0 Key136=0:0 Key137=0:0 [altgr] Key8=0:0 Key9=65307:27 Key10=124:124 Key11=64:64 Key12=35:35 Key13=188:188 Key14=189:189 Key15=94:94 Key16=123:123 Key17=91:91 Key18=123:123 Key19=125:125 Key20=92:92 Key21=65115:184 Key22=65288:8 Key23=65289:9 Key24=64:64 Key25=435:322 Key26=8364:8364 Key27=182:182 Key28=956:359 Key29=2299:8592 Key30=2302:8595 Key31=2301:8594 Key32=5053:339 Key33=254:254 Key34=91:91 Key35=93:93 Key36=65293:13 Key37=65507:0 Key38=230:230 Key39=223:223 Key40=240:240 Key41=496:273 Key42=959:331 Key43=689:295 Key44=106:106 Key45=930:312 Key46=435:322 Key47=65105:180 Key48=65105:180 Key49=172:172 Key50=65505:0 Key51=65104:96 Key52=171:171 Key53=187:187 Key54=162:162 Key55=2770:8220 Key56=2771:8221 Key57=110:110 Key58=65115:184 Key59=2211:0 Key60=183:183 Key61=65107:126 Key62=65506:0 Key63=65450:42 Key64=65513:0 Key65=32:32 Key66=65509:0 Key67=65470:0 Key68=65471:0 Key69=65472:0 Key70=65473:0 Key71=65474:0 Key72=65475:0 Key73=65476:0 Key74=65477:0 Key75=65478:0 Key76=65479:0 Key77=65407:0 Key78=65300:0 Key79=65429:0 Key80=65431:0 Key81=65434:0 Key82=65453:45 Key83=65430:0 Key84=65437:0 Key85=65432:0 Key86=65451:43 Key87=65436:0 Key88=65433:0 Key89=65435:0 Key90=65438:0 Key91=65439:0 Key92=0:0 Key93=65406:0 Key94=92:92 Key95=65480:0 Key96=65481:0 Key97=65360:0 Key98=65362:0 Key99=65365:0 Key100=65361:0 Key101=0:0 Key102=65363:0 Key103=65367:0 Key104=65364:0 Key105=65366:0 Key106=65379:0 Key107=65535:127 Key108=65421:13 Key109=65508:0 Key110=65299:0 Key111=65377:0 Key112=65455:47 Key113=65027:0 Key114=0:0 Key115=65515:0 Key116=65516:0 Key117=65383:0 Key118=0:0 Key119=0:0 Key120=0:0 Key121=0:0 Key122=0:0 Key123=0:0 Key124=65027:0 Key125=0:0 Key126=65469:61 Key127=0:0 Key128=0:0 Key129=0:0 Key130=0:0 Key131=0:0 Key132=0:0 Key133=0:0 Key134=0:0 Key135=0:0 Key136=0:0 Key137=0:0 [capslock] Key8=0:0 Key9=65307:27 Key10=38:38 Key11=201:201 Key12=34:34 Key13=39:39 Key14=40:40 Key15=167:167 Key16=200:200 Key17=33:33 Key18=199:199 Key19=192:192 Key20=41:41 Key21=45:45 Key22=65288:8 Key23=65289:9 Key24=65:65 Key25=90:90 Key26=69:69 Key27=82:82 Key28=84:84 Key29=89:89 Key30=85:85 Key31=73:73 Key32=79:79 Key33=80:80 Key34=65106:94 Key35=36:36 Key36=65293:13 Key37=65507:0 Key38=81:81 Key39=83:83 Key40=68:68 Key41=70:70 Key42=71:71 Key43=72:72 Key44=74:74 Key45=75:75 Key46=76:76 Key47=77:77 Key48=217:217 Key49=178:178 Key50=65505:0 Key51=924:0 Key52=87:87 Key53=88:88 Key54=67:67 Key55=86:86 Key56=66:66 Key57=78:78 Key58=44:44 Key59=59:59 Key60=58:58 Key61=61:61 Key62=65506:0 Key63=65450:42 Key64=65513:0 Key65=32:32 Key66=65509:0 Key67=65470:0 Key68=65471:0 Key69=65472:0 Key70=65473:0 Key71=65474:0 Key72=65475:0 Key73=65476:0 Key74=65477:0 Key75=65478:0 Key76=65479:0 Key77=65407:0 Key78=65300:0 Key79=65429:0 Key80=65431:0 Key81=65434:0 Key82=65453:45 Key83=65430:0 Key84=65437:0 Key85=65432:0 Key86=65451:43 Key87=65436:0 Key88=65433:0 Key89=65435:0 Key90=65438:0 Key91=65439:0 Key92=0:0 Key93=65406:0 Key94=60:60 Key95=65480:0 Key96=65481:0 Key97=65360:0 Key98=65362:0 Key99=65365:0 Key100=65361:0 Key101=0:0 Key102=65363:0 Key103=65367:0 Key104=65364:0 Key105=65366:0 Key106=65379:0 Key107=65535:127 Key108=65421:13 Key109=65508:0 Key110=65299:0 Key111=65377:0 Key112=65455:47 Key113=65027:0 Key114=0:0 Key115=65515:0 Key116=65516:0 Key117=65383:0 Key118=0:0 Key119=0:0 Key120=0:0 Key121=0:0 Key122=0:0 Key123=0:0 Key124=65027:0 Key125=0:0 Key126=65469:61 Key127=0:0 Key128=0:0 Key129=0:0 Key130=0:0 Key131=0:0 Key132=0:0 Key133=0:0 Key134=0:0 Key135=0:0 Key136=0:0 Key137=0:0 [shiftcapslock] Key8=0:0 Key9=65307:27 Key10=49:49 Key11=50:50 Key12=51:51 Key13=52:52 Key14=53:53 Key15=54:54 Key16=55:55 Key17=56:56 Key18=57:57 Key19=48:48 Key20=176:176 Key21=95:95 Key22=65288:8 Key23=65056:0 Key24=97:97 Key25=122:122 Key26=101:101 Key27=114:114 Key28=116:116 Key29=121:121 Key30=117:117 Key31=105:105 Key32=111:111 Key33=112:112 Key34=65111:168 Key35=42:42 Key36=65293:13 Key37=65507:0 Key38=113:113 Key39=115:115 Key40=100:100 Key41=102:102 Key42=103:103 Key43=104:104 Key44=106:106 Key45=107:107 Key46=108:108 Key47=109:109 Key48=37:37 Key49=179:179 Key50=65505:0 Key51=163:163 Key52=119:119 Key53=120:120 Key54=99:99 Key55=118:118 Key56=98:98 Key57=110:110 Key58=63:63 Key59=46:46 Key60=47:47 Key61=43:43 Key62=65506:0 Key63=65450:42 Key64=65511:0 Key65=32:32 Key66=65509:0 Key67=65470:0 Key68=65471:0 Key69=65472:0 Key70=65473:0 Key71=65474:0 Key72=65475:0 Key73=65476:0 Key74=65477:0 Key75=65478:0 Key76=65479:0 Key77=65273:0 Key78=65300:0 Key79=65463:55 Key80=65464:56 Key81=65465:57 Key82=65453:45 Key83=65460:52 Key84=65461:53 Key85=65462:54 Key86=65451:43 Key87=65457:49 Key88=65458:50 Key89=65459:51 Key90=65456:48 Key91=65454:46 Key92=0:0 Key93=65406:0 Key94=62:62 Key95=65480:0 Key96=65481:0 Key97=65360:0 Key98=65362:0 Key99=65365:0 Key100=65361:0 Key101=0:0 Key102=65363:0 Key103=65367:0 Key104=65364:0 Key105=65366:0 Key106=65379:0 Key107=65535:127 Key108=65421:13 Key109=65508:0 Key110=65299:0 Key111=65377:0 Key112=65455:47 Key113=65027:0 Key114=0:0 Key115=65515:0 Key116=65516:0 Key117=65383:0 Key118=0:0 Key119=0:0 Key120=0:0 Key121=0:0 Key122=0:0 Key123=0:0 Key124=65027:0 Key125=65513:0 Key126=65469:61 Key127=65515:0 Key128=65517:0 Key129=0:0 Key130=0:0 Key131=0:0 Key132=0:0 Key133=0:0 Key134=0:0 Key135=0:0 Key136=0:0 Key137=0:0 xrdp-0.6.0/instfiles/pam.d/000077500000000000000000000000001203155130500154645ustar00rootroot00000000000000xrdp-0.6.0/instfiles/pam.d/Makefile.am000066400000000000000000000003411203155130500175160ustar00rootroot00000000000000EXTRA_DIST = xrdp-sesman if SESMAN_NOPAM PAMFILE = else if SESMAN_PAMUSERPASS PAMFILE = else if SESMAN_KERBEROS PAMFILE = else PAMFILE = xrdp-sesman endif endif endif pamddir=$(sysconfdir)/pam.d pamd_DATA = \ $(PAMFILE) xrdp-0.6.0/instfiles/pam.d/xrdp-sesman000066400000000000000000000002011203155130500176410ustar00rootroot00000000000000#%PAM-1.0 auth required pam_unix.so shadow nullok auth required pam_env.so readenv=1 account required pam_unix.so xrdp-0.6.0/instfiles/xrdp.sh000077500000000000000000000043731203155130500160100ustar00rootroot00000000000000#!/bin/sh # xrdp control script # Written : 1-13-2006 - Mark Balliet - posicat@pobox.com # maintaned by Jay Sorg # chkconfig: 2345 11 89 # description: starts xrdp SBINDIR=/usr/local/sbin LOG=/dev/null CFGDIR=/etc/xrdp if ! test -x $SBINDIR/xrdp then echo "xrdp is not executable" exit 0 fi if ! test -x $SBINDIR/xrdp-sesman then echo "xrdp-sesman is not executable" exit 0 fi if ! test -x $CFGDIR/startwm.sh then echo "startwm.sh is not executable" exit 0 fi xrdp_start() { echo -n "Starting: xrdp and sesman . . " $SBINDIR/xrdp >> $LOG $SBINDIR/xrdp-sesman >> $LOG echo "." sleep 1 return 0; } xrdp_stop() { echo -n "Stopping: xrdp and sesman . . " $SBINDIR/xrdp-sesman --kill >> $LOG $SBINDIR/xrdp --kill >> $LOG echo "." return 0; } is_xrdp_running() { ps u --noheading -C xrdp | grep -q -i xrdp if test $? -eq 0 then return 1; else return 0; fi } is_sesman_running() { ps u --noheading -C xrdp-sesman | grep -q -i xrdp-sesman if test $? -eq 0 then return 1; else return 0; fi } check_up() { # Cleanup : If sesman isn't running, but the pid exists, erase it. is_sesman_running if test $? -eq 0 then if test -e /var/run/xrdp-sesman.pid then rm /var/run/xrdp-sesman.pid fi fi # Cleanup : If xrdp isn't running, but the pid exists, erase it. is_xrdp_running if test $? -eq 0 then if test -e /var/run/xrdp.pid then rm /var/run/xrdp.pid fi fi return 0; } case "$1" in start) check_up is_xrdp_running if ! test $? -eq 0 then echo "xrdp is already loaded" exit 1 fi is_sesman_running if ! test $? -eq 0 then echo "sesman is already loaded" exit 1 fi xrdp_start ;; stop) check_up is_xrdp_running if test $? -eq 0 then echo "xrdp is not loaded." fi is_sesman_running if test $? -eq 0 then echo "sesman is not loaded." fi xrdp_stop ;; force-reload|restart) check_up echo "Restarting xrdp ..." xrdp_stop is_xrdp_running while ! test $? -eq 0 do check_up sleep 1 is_xrdp_running done xrdp_start ;; *) echo "Usage: xrdp.sh {start|stop|restart|force-reload}" exit 1 esac exit 0 xrdp-0.6.0/keygen/000077500000000000000000000000001203155130500137475ustar00rootroot00000000000000xrdp-0.6.0/keygen/Makefile.am000066400000000000000000000005251203155130500160050ustar00rootroot00000000000000 AM_CFLAGS = \ -DXRDP_CFG_PATH=\"${sysconfdir}/xrdp\" \ -DXRDP_SBIN_PATH=\"${sbindir}\" \ -DXRDP_SHARE_PATH=\"${datadir}/xrdp\" \ -DXRDP_PID_PATH=\"${localstatedir}/run\" INCLUDES = \ -I$(top_srcdir)/common bin_PROGRAMS = \ xrdp-keygen xrdp_keygen_SOURCES = keygen.c xrdp_keygen_LDADD = \ $(top_srcdir)/common/libcommon.la xrdp-0.6.0/keygen/keygen.c000066400000000000000000000301321203155130500153740ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2007-2010 rsa key generator for xrdp */ /* references: http://www.securiteam.com/windowsntfocus/5EP010KG0G.html */ #include "os_calls.h" #include "ssl_calls.h" #include "arch.h" #include "list.h" #include "file.h" #define MY_KEY_SIZE 512 static tui8 g_exponent[4] = { 0x01, 0x00, 0x01, 0x00 }; static tui8 g_ppk_e[4] = { 0x5B, 0x7B, 0x88, 0xC0 }; static tui8 g_ppk_n[72] = { 0x3D, 0x3A, 0x5E, 0xBD, 0x72, 0x43, 0x3E, 0xC9, 0x4D, 0xBB, 0xC1, 0x1E, 0x4A, 0xBA, 0x5F, 0xCB, 0x3E, 0x88, 0x20, 0x87, 0xEF, 0xF5, 0xC1, 0xE2, 0xD7, 0xB7, 0x6B, 0x9A, 0xF2, 0x52, 0x45, 0x95, 0xCE, 0x63, 0x65, 0x6B, 0x58, 0x3A, 0xFE, 0xEF, 0x7C, 0xE7, 0xBF, 0xFE, 0x3D, 0xF6, 0x5C, 0x7D, 0x6C, 0x5E, 0x06, 0x09, 0x1A, 0xF5, 0x61, 0xBB, 0x20, 0x93, 0x09, 0x5F, 0x05, 0x6D, 0xEA, 0x87, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; static tui8 g_ppk_d[108] = { 0x87, 0xA7, 0x19, 0x32, 0xDA, 0x11, 0x87, 0x55, 0x58, 0x00, 0x16, 0x16, 0x25, 0x65, 0x68, 0xF8, 0x24, 0x3E, 0xE6, 0xFA, 0xE9, 0x67, 0x49, 0x94, 0xCF, 0x92, 0xCC, 0x33, 0x99, 0xE8, 0x08, 0x60, 0x17, 0x9A, 0x12, 0x9F, 0x24, 0xDD, 0xB1, 0x24, 0x99, 0xC7, 0x3A, 0xB8, 0x0A, 0x7B, 0x0D, 0xDD, 0x35, 0x07, 0x79, 0x17, 0x0B, 0x51, 0x9B, 0xB3, 0xC7, 0x10, 0x01, 0x13, 0xE7, 0x3F, 0xF3, 0x5F, 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 }; static tui8 g_testkey[176] = { 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x06, 0x00, 0x5c, 0x00, 0x52, 0x53, 0x41, 0x31, 0x48, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x79, 0x6f, 0xb4, 0xdf, 0xa6, 0x95, 0xb9, 0xa9, 0x61, 0xe3, 0xc4, 0x5e, 0xff, 0x6b, 0xd8, 0x81, 0x8a, 0x12, 0x4a, 0x93, 0x42, 0x97, 0x18, 0x93, 0xac, 0xd1, 0x3a, 0x38, 0x3c, 0x68, 0x50, 0x19, 0x31, 0xb6, 0x84, 0x51, 0x79, 0xfb, 0x1c, 0xe7, 0xe3, 0x99, 0x20, 0xc7, 0x84, 0xdf, 0xd1, 0xaa, 0xb5, 0x15, 0xef, 0x47, 0x7e, 0xfc, 0x88, 0xeb, 0x29, 0xc3, 0x27, 0x5a, 0x35, 0xf8, 0xfd, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x48, 0x00, 0x32, 0x3b, 0xde, 0x6f, 0x18, 0x97, 0x1e, 0xc3, 0x6b, 0x2b, 0x2d, 0xe4, 0xfc, 0x2d, 0xa2, 0x8e, 0x32, 0x3c, 0xf3, 0x1b, 0x24, 0x90, 0x57, 0x4d, 0x8e, 0xe4, 0x69, 0xfc, 0x16, 0x8d, 0x41, 0x92, 0x78, 0xc7, 0x9c, 0xb4, 0x26, 0xff, 0xe8, 0x3e, 0xa1, 0x8a, 0xf5, 0x57, 0xc0, 0x7f, 0x3e, 0x21, 0x17, 0x32, 0x30, 0x6f, 0x79, 0xe1, 0x36, 0xcd, 0xb6, 0x8e, 0xbe, 0x57, 0x57, 0xd2, 0xa9, 0x36 }; /* this is the installed signature */ char inst_pub_sig[]="0x6a,0x41,0xb1,0x43,0xcf,0x47,0x6f,0xf1,0xe6,0xcc,0xa1,\ 0x72,0x97,0xd9,0xe1,0x85,0x15,0xb3,0xc2,0x39,0xa0,0xa6,0x26,0x1a,0xb6,\ 0x49,0x01,0xfa,0xa6,0xda,0x60,0xd7,0x45,0xf7,0x2c,0xee,0xe4,0x8e,0x64,\ 0x2e,0x37,0x49,0xf0,0x4c,0x94,0x6f,0x08,0xf5,0x63,0x4c,0x56,0x29,0x55,\ 0x5a,0x63,0x41,0x2c,0x20,0x65,0x95,0x99,0xb1,0x15,0x7c"; /*****************************************************************************/ static int APP_CC out_params(void) { g_writeln(""); g_writeln("xrdp rsa key gen utility examples"); g_writeln(" xrdp-keygen xrdp ['path and file name' | auto]"); g_writeln(" xrdp-keygen test"); g_writeln(""); return 0; } /*****************************************************************************/ /* this is the special key signing algorithm */ static int APP_CC sign_key(char* e_data, int e_len, char* n_data, int n_len, char* sign_data, int sign_len) { char* key; char* md5_final; void* md5; if ((e_len != 4) || (n_len != 64) || (sign_len != 64)) { return 1; } key = (char*)g_malloc(176, 0); md5_final = (char*)g_malloc(64, 0); md5 = ssl_md5_info_create(); /* copy the test key */ g_memcpy(key, g_testkey, 176); /* replace e and n */ g_memcpy(key + 32, e_data, 4); g_memcpy(key + 36, n_data, 64); ssl_md5_clear(md5); /* the first 108 bytes */ ssl_md5_transform(md5, key, 108); /* set the whole thing with 0xff */ g_memset(md5_final, 0xff, 64); /* digest 16 bytes */ ssl_md5_complete(md5, md5_final); /* set non 0xff array items */ md5_final[16] = 0; md5_final[62] = 1; md5_final[63] = 0; /* encrypt */ ssl_mod_exp(sign_data, 64, md5_final, 64, (char*)g_ppk_n, 64, (char*)g_ppk_d, 64); /* cleanup */ ssl_md5_info_delete(md5); g_free(key); g_free(md5_final); return 0; } /*****************************************************************************/ static int APP_CC write_out_line(int fd, char* name, char* data, int len) { int max; int error; int index; int data_item; int buf_pos; char* buf; char* text; text = (char*)g_malloc(256, 0); max = len; max = max * 10; buf_pos = g_strlen(name); max = max + buf_pos + 16; buf = (char*)g_malloc(max, 0); g_strncpy(buf, name, max - 1); buf[buf_pos] = '='; buf_pos++; for (index = 0; index < len; index++) { data_item = (tui8)(data[index]); g_snprintf(text, 255, "0x%2.2x", data_item); if (index != 0) { buf[buf_pos] = ','; buf_pos++; } buf[buf_pos] = text[0]; buf_pos++; buf[buf_pos] = text[1]; buf_pos++; buf[buf_pos] = text[2]; buf_pos++; buf[buf_pos] = text[3]; buf_pos++; } buf[buf_pos] = '\n'; buf_pos++; buf[buf_pos] = 0; error = g_file_write(fd, buf, buf_pos) == -1; g_free(buf); g_free(text); return error; } /*****************************************************************************/ static int APP_CC save_all(char* e_data, int e_len, char* n_data, int n_len, char* d_data, int d_len, char* sign_data, int sign_len, const char* path_and_file_name) { int fd; char filename[256]; if (path_and_file_name == 0) { g_strncpy(filename, "rsakeys.ini", 255); } else { g_strncpy(filename, path_and_file_name, 255); } g_writeln("saving to %s", filename); g_writeln(""); if (g_file_exist(filename)) { if (g_file_delete(filename) == 0) { g_writeln("problem deleting %s, maybe no rights", filename); return 1; } } fd = g_file_open(filename); if (fd > 0) { if (g_file_write(fd, "[keys]\n", 7) == -1) { g_writeln("problem writing to %s, maybe no rights", filename); return 1; } write_out_line(fd, "pub_exp", e_data, e_len); write_out_line(fd, "pub_mod", n_data, n_len); write_out_line(fd, "pub_sig", sign_data, sign_len); write_out_line(fd, "pri_exp", d_data, d_len); } else { g_writeln("problem opening %s, maybe no rights", filename); return 1; } g_file_close(fd); return 0; } /*****************************************************************************/ static int APP_CC key_gen(const char* path_and_file_name) { char* e_data; char* n_data; char* d_data; char* sign_data; int e_len; int n_len; int d_len; int sign_len; int error; e_data = (char*)g_exponent; n_data = (char*)g_malloc(64, 0); d_data = (char*)g_malloc(64, 0); sign_data = (char*)g_malloc(64, 0); e_len = 4; n_len = 64; d_len = 64; sign_len = 64; error = 0; g_writeln(""); g_writeln("Generating %d bit rsa key...", MY_KEY_SIZE); g_writeln(""); if (error == 0) { error = ssl_gen_key_xrdp1(MY_KEY_SIZE, e_data, e_len, n_data, n_len, d_data, d_len); if (error != 0) { g_writeln("error %d in key_gen, ssl_gen_key_xrdp1", error); } } if (error == 0) { g_writeln("ssl_gen_key_xrdp1 ok"); g_writeln(""); error = sign_key(e_data, e_len, n_data, n_len, sign_data, sign_len); if (error != 0) { g_writeln("error %d in key_gen, sign_key", error); } } if (error == 0) { error = save_all(e_data, e_len, n_data, n_len, d_data, d_len, sign_data, sign_len, path_and_file_name); if (error != 0) { g_writeln("error %d in key_gen, save_all", error); } } g_free(n_data); g_free(d_data); g_free(sign_data); return error; } /*****************************************************************************/ /* returns boolean */ static int APP_CC key_gen_run_it(void) { int fd; int index; int rv; struct list* names; struct list* values; char* name; char* value; if (!g_file_exist("/etc/xrdp/rsakeys.ini")) { return 1; } if (g_file_get_size("/etc/xrdp/rsakeys.ini") < 10) { return 1; } fd = g_file_open("/etc/xrdp/rsakeys.ini"); if (fd < 0) { return 1; } rv = 0; names = list_create(); names->auto_free = 1; values = list_create(); values->auto_free = 1; if (file_read_section(fd, "keys", names, values) == 0) { for (index = 0; index < names->count; index++) { name = (char*)list_get_item(names, index); value = (char*)list_get_item(values, index); if (g_strcasecmp(name, "pub_sig") == 0) { if (g_strcasecmp(value, inst_pub_sig) == 0) { rv = 1; } } } } else { g_writeln("error reading keys section of rsakeys.ini"); } list_delete(names); list_delete(values); g_file_close(fd); return rv; } /*****************************************************************************/ static int APP_CC key_gen_auto(void) { if (key_gen_run_it()) { return key_gen("/etc/xrdp/rsakeys.ini"); } g_writeln("xrdp-keygen does not need to run"); return 0; } /*****************************************************************************/ static int APP_CC key_test(void) { char* md5_final; char* sig; void* md5; md5_final = (char*)g_malloc(64, 0); sig = (char*)g_malloc(64, 0); md5 = ssl_md5_info_create(); g_writeln("original key is:"); g_hexdump((char*)g_testkey, 176); g_writeln("original exponent is:"); g_hexdump((char*)g_testkey + 32, 4); g_writeln("original modulus is:"); g_hexdump((char*)g_testkey + 36, 64); g_writeln("original signature is:"); g_hexdump((char*)g_testkey + 112, 64); ssl_md5_clear(md5); ssl_md5_transform(md5, (char*)g_testkey, 108); g_memset(md5_final, 0xff, 64); ssl_md5_complete(md5, md5_final); g_writeln("md5 hash of first 108 bytes of this key is:"); g_hexdump(md5_final, 16); md5_final[16] = 0; md5_final[62] = 1; md5_final[63] = 0; ssl_mod_exp(sig, 64, md5_final, 64, (char*)g_ppk_n, 64, (char*)g_ppk_d, 64); g_writeln("produced signature(this should match original \ signature above) is:"); g_hexdump(sig, 64); g_memset(md5_final, 0, 64); ssl_mod_exp(md5_final, 64, (char*)g_testkey + 112, 64, (char*)g_ppk_n, 64, (char*)g_ppk_e, 4); g_writeln("decrypted hash of first 108 bytes of this key is:"); g_hexdump(md5_final, 64); ssl_md5_info_delete(md5); g_free(md5_final); g_free(sig); return 0; } /*****************************************************************************/ int DEFAULT_CC main(int argc, char** argv) { if (argc > 1) { if (g_strcasecmp(argv[1], "xrdp") == 0) { if (argc > 2) { if (g_strcasecmp(argv[2], "auto") == 0) { if (g_getuid() != 0) { g_writeln("must run as root"); return 0; } return key_gen_auto(); } else { return key_gen(argv[2]); } } else { return key_gen(0); } } else if (g_strcasecmp(argv[1], "test") == 0) { return key_test(); } } out_params(); return 0; } xrdp-0.6.0/libxrdp/000077500000000000000000000000001203155130500141315ustar00rootroot00000000000000xrdp-0.6.0/libxrdp/Makefile.am000066400000000000000000000011651203155130500161700ustar00rootroot00000000000000EXTRA_DIST = libxrdp.h libxrdpinc.h if XRDP_DEBUG EXTRA_DEFINES = -DXRDP_DEBUG else EXTRA_DEFINES = -DXRDP_NODEBUG endif AM_CFLAGS = \ -DXRDP_CFG_PATH=\"${sysconfdir}/xrdp\" \ -DXRDP_SBIN_PATH=\"${sbindir}\" \ -DXRDP_SHARE_PATH=\"${datadir}/xrdp\" \ -DXRDP_PID_PATH=\"${localstatedir}/run\" \ $(EXTRA_DEFINES) INCLUDES = \ -I$(top_srcdir)/common lib_LTLIBRARIES = \ libxrdp.la libxrdp_la_SOURCES = \ libxrdp.c \ xrdp_channel.c \ xrdp_iso.c \ xrdp_mcs.c \ xrdp_orders.c \ xrdp_rdp.c \ xrdp_sec.c \ xrdp_tcp.c \ xrdp_bitmap_compress.c libxrdp_la_LIBADD = \ $(top_srcdir)/common/libcommon.la xrdp-0.6.0/libxrdp/libxrdp.c000066400000000000000000000557041203155130500157540ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2004-2010 this is the interface to libxrdp */ #include "libxrdp.h" /******************************************************************************/ struct xrdp_session* EXPORT_CC libxrdp_init(tbus id, struct trans* trans) { struct xrdp_session* session; session = (struct xrdp_session*)g_malloc(sizeof(struct xrdp_session), 1); session->id = id; session->rdp = xrdp_rdp_create(session, trans); session->orders = xrdp_orders_create(session, (struct xrdp_rdp*)session->rdp); session->client_info = &(((struct xrdp_rdp*)session->rdp)->client_info); make_stream(session->s); init_stream(session->s, 8192 * 2); return session; } /******************************************************************************/ int EXPORT_CC libxrdp_exit(struct xrdp_session* session) { if (session == 0) { return 0; } xrdp_orders_delete((struct xrdp_orders*)session->orders); xrdp_rdp_delete((struct xrdp_rdp*)session->rdp); free_stream(session->s); g_free(session); return 0; } /******************************************************************************/ int EXPORT_CC libxrdp_disconnect(struct xrdp_session* session) { return xrdp_rdp_disconnect((struct xrdp_rdp*)session->rdp); } /******************************************************************************/ int EXPORT_CC libxrdp_process_incomming(struct xrdp_session* session) { return xrdp_rdp_incoming((struct xrdp_rdp*)session->rdp); } /******************************************************************************/ int EXPORT_CC libxrdp_process_data(struct xrdp_session* session) { int cont; int rv; int code; int term; term = 0; cont = 1; rv = 0; while ((cont || !session->up_and_running) && !term) { if (session->is_term != 0) { if (session->is_term()) { term = 1; } } code = 0; if (xrdp_rdp_recv((struct xrdp_rdp*)session->rdp, session->s, &code) != 0) { rv = 1; break; } DEBUG(("libxrdp_process_data code %d", code)); switch (code) { case -1: xrdp_rdp_send_demand_active((struct xrdp_rdp*)session->rdp); session->up_and_running = 0; break; case 0: break; case RDP_PDU_CONFIRM_ACTIVE: /* 3 */ xrdp_rdp_process_confirm_active((struct xrdp_rdp*)session->rdp, session->s); break; case RDP_PDU_DATA: /* 7 */ if (xrdp_rdp_process_data((struct xrdp_rdp*)session->rdp, session->s) != 0) { DEBUG(("libxrdp_process_data returned non zero")); cont = 0; term = 1; } break; default: g_writeln("unknown in libxrdp_process_data"); break; } if (cont) { cont = (session->s->next_packet != 0) && (session->s->next_packet < session->s->end); } } return rv; } /******************************************************************************/ int EXPORT_CC libxrdp_send_palette(struct xrdp_session* session, int* palette) { int i = 0; int color = 0; struct stream* s = (struct stream *)NULL; if (session->client_info->bpp > 8) { return 0; } DEBUG(("libxrdp_send_palette sending palette")); /* clear orders */ libxrdp_orders_force_send(session); make_stream(s); init_stream(s, 8192); xrdp_rdp_init_data((struct xrdp_rdp*)session->rdp, s); out_uint16_le(s, RDP_UPDATE_PALETTE); out_uint16_le(s, 0); out_uint16_le(s, 256); /* # of colors */ out_uint16_le(s, 0); for (i = 0; i < 256; i++) { color = palette[i]; out_uint8(s, color >> 16); out_uint8(s, color >> 8); out_uint8(s, color); } s_mark_end(s); xrdp_rdp_send_data((struct xrdp_rdp*)session->rdp, s, RDP_DATA_PDU_UPDATE); free_stream(s); /* send the orders palette too */ libxrdp_orders_init(session); libxrdp_orders_send_palette(session, palette, 0); libxrdp_orders_send(session); return 0; } /******************************************************************************/ int EXPORT_CC libxrdp_send_bell(struct xrdp_session* session) { struct stream* s = (struct stream *)NULL; DEBUG(("libxrdp_send_bell sending bell signal")); /* see MS documentation: Server play sound PDU, TS_PLAY_SOUND_PDU_DATA */ make_stream(s); init_stream(s, 8192); if (xrdp_rdp_init_data((struct xrdp_rdp*)session->rdp, s) != 0) { free_stream(s); return 1; } out_uint32_le(s, 440); /* frequency */ out_uint32_le(s, 100); /* duration (ms) */ s_mark_end(s); if (xrdp_rdp_send_data((struct xrdp_rdp*)session->rdp, s, RDP_DATA_PDU_PLAY_SOUND) != 0) { free_stream(s); return 1; } free_stream(s); return 0; } /*****************************************************************************/ int EXPORT_CC libxrdp_send_bitmap(struct xrdp_session* session, int width, int height, int bpp, char* data, int x, int y, int cx, int cy) { int line_size = 0; int i = 0; int j = 0; int total_lines = 0; int lines_sending = 0; int Bpp = 0; int e = 0; int bufsize = 0; int total_bufsize = 0; int num_updates = 0; char* p_num_updates = (char *)NULL; char* p = (char *)NULL; char* q = (char *)NULL; struct stream* s = (struct stream *)NULL; struct stream* temp_s = (struct stream *)NULL; DEBUG(("libxrdp_send_bitmap sending bitmap")); Bpp = (bpp + 7) / 8; e = width % 4; if (e != 0) { e = 4 - e; } line_size = width * Bpp; make_stream(s); init_stream(s, 8192); if (session->client_info->use_bitmap_comp) { make_stream(temp_s); init_stream(temp_s, 65536); i = 0; if (cy <= height) { i = cy; } while (i > 0) { total_bufsize = 0; num_updates = 0; xrdp_rdp_init_data((struct xrdp_rdp*)session->rdp, s); out_uint16_le(s, RDP_UPDATE_BITMAP); p_num_updates = s->p; out_uint8s(s, 2); /* num_updates set later */ do { if (session->client_info->op1) { s_push_layer(s, channel_hdr, 18); } else { s_push_layer(s, channel_hdr, 26); } p = s->p; lines_sending = xrdp_bitmap_compress(data, width, height, s, bpp, 4096 - total_bufsize, i - 1, temp_s, e); if (lines_sending == 0) { break; } num_updates++; bufsize = s->p - p; total_bufsize += bufsize; i = i - lines_sending; s_mark_end(s); s_pop_layer(s, channel_hdr); out_uint16_le(s, x); /* left */ out_uint16_le(s, y + i); /* top */ out_uint16_le(s, (x + cx) - 1); /* right */ out_uint16_le(s, (y + i + lines_sending) - 1); /* bottom */ out_uint16_le(s, width + e); /* width */ out_uint16_le(s, lines_sending); /* height */ out_uint16_le(s, bpp); /* bpp */ if (session->client_info->op1) { out_uint16_le(s, 0x401); /* compress */ out_uint16_le(s, bufsize); /* compressed size */ j = (width + e) * Bpp; j = j * lines_sending; } else { out_uint16_le(s, 0x1); /* compress */ out_uint16_le(s, bufsize + 8); out_uint8s(s, 2); /* pad */ out_uint16_le(s, bufsize); /* compressed size */ j = (width + e) * Bpp; out_uint16_le(s, j); /* line size */ j = j * lines_sending; out_uint16_le(s, j); /* final size */ } if (j > 32768) { g_writeln("error, decompressed size too big, its %d", j); } if (bufsize > 8192) { g_writeln("error, compressed size too big, its %d", bufsize); } s->p = s->end; } while (total_bufsize < 4096 && i > 0); p_num_updates[0] = num_updates; p_num_updates[1] = num_updates >> 8; xrdp_rdp_send_data((struct xrdp_rdp*)session->rdp, s, RDP_DATA_PDU_UPDATE); if (total_bufsize > 8192) { g_writeln("error, total compressed size too big, its %d", total_bufsize); } } free_stream(temp_s); } else { total_lines = height; i = 0; p = data; if (line_size > 0 && total_lines > 0) { while (i < total_lines) { lines_sending = 4096 / (line_size + e * Bpp); if (i + lines_sending > total_lines) { lines_sending = total_lines - i; } p = p + line_size * lines_sending; xrdp_rdp_init_data((struct xrdp_rdp*)session->rdp, s); out_uint16_le(s, RDP_UPDATE_BITMAP); out_uint16_le(s, 1); /* num updates */ out_uint16_le(s, x); out_uint16_le(s, y + i); out_uint16_le(s, (x + cx) - 1); out_uint16_le(s, (y + i + lines_sending) - 1); out_uint16_le(s, width + e); out_uint16_le(s, lines_sending); out_uint16_le(s, bpp); /* bpp */ out_uint16_le(s, 0); /* compress */ out_uint16_le(s, (line_size + e * Bpp) * lines_sending); /* bufsize */ q = p; for (j = 0; j < lines_sending; j++) { q = q - line_size; out_uint8a(s, q, line_size); /* B_ENDIAN doesn't work here, todo */ out_uint8s(s, e * Bpp); } s_mark_end(s); xrdp_rdp_send_data((struct xrdp_rdp*)session->rdp, s, RDP_DATA_PDU_UPDATE); i = i + lines_sending; } } } free_stream(s); return 0; } /*****************************************************************************/ int EXPORT_CC libxrdp_send_pointer(struct xrdp_session* session, int cache_idx, char* data, char* mask, int x, int y) { struct stream* s; char* p; int i; int j; DEBUG(("libxrdp_send_pointer sending cursor")); make_stream(s); init_stream(s, 8192); xrdp_rdp_init_data((struct xrdp_rdp*)session->rdp, s); out_uint16_le(s, RDP_POINTER_COLOR); out_uint16_le(s, 0); /* pad */ out_uint16_le(s, cache_idx); /* cache_idx */ out_uint16_le(s, x); out_uint16_le(s, y); out_uint16_le(s, 32); out_uint16_le(s, 32); out_uint16_le(s, 128); out_uint16_le(s, 3072); p = data; for (i = 0; i < 32; i++) { for (j = 0; j < 32; j++) { out_uint8(s, *p); p++; out_uint8(s, *p); p++; out_uint8(s, *p); p++; } } out_uint8a(s, mask, 128); /* mask */ s_mark_end(s); xrdp_rdp_send_data((struct xrdp_rdp*)session->rdp, s, RDP_DATA_PDU_POINTER); free_stream(s); return 0; } /*****************************************************************************/ int EXPORT_CC libxrdp_set_pointer(struct xrdp_session* session, int cache_idx) { struct stream* s; DEBUG(("libxrdp_set_pointer sending cursor index")); make_stream(s); init_stream(s, 8192); xrdp_rdp_init_data((struct xrdp_rdp*)session->rdp, s); out_uint16_le(s, RDP_POINTER_CACHED); out_uint16_le(s, 0); /* pad */ out_uint16_le(s, cache_idx); /* cache_idx */ s_mark_end(s); xrdp_rdp_send_data((struct xrdp_rdp*)session->rdp, s, RDP_DATA_PDU_POINTER); free_stream(s); return 0; } /******************************************************************************/ int EXPORT_CC libxrdp_orders_init(struct xrdp_session* session) { return xrdp_orders_init((struct xrdp_orders*)session->orders); } /******************************************************************************/ int EXPORT_CC libxrdp_orders_send(struct xrdp_session* session) { return xrdp_orders_send((struct xrdp_orders*)session->orders); } /******************************************************************************/ int EXPORT_CC libxrdp_orders_force_send(struct xrdp_session* session) { return xrdp_orders_force_send((struct xrdp_orders*)session->orders); } /******************************************************************************/ int EXPORT_CC libxrdp_orders_rect(struct xrdp_session* session, int x, int y, int cx, int cy, int color, struct xrdp_rect* rect) { return xrdp_orders_rect((struct xrdp_orders*)session->orders, x, y, cx, cy, color, rect); } /******************************************************************************/ int EXPORT_CC libxrdp_orders_screen_blt(struct xrdp_session* session, int x, int y, int cx, int cy, int srcx, int srcy, int rop, struct xrdp_rect* rect) { return xrdp_orders_screen_blt((struct xrdp_orders*)session->orders, x, y, cx, cy, srcx, srcy, rop, rect); } /******************************************************************************/ int EXPORT_CC libxrdp_orders_pat_blt(struct xrdp_session* session, int x, int y, int cx, int cy, int rop, int bg_color, int fg_color, struct xrdp_brush* brush, struct xrdp_rect* rect) { return xrdp_orders_pat_blt((struct xrdp_orders*)session->orders, x, y, cx, cy, rop, bg_color, fg_color, brush, rect); } /******************************************************************************/ int EXPORT_CC libxrdp_orders_dest_blt(struct xrdp_session* session, int x, int y, int cx, int cy, int rop, struct xrdp_rect* rect) { return xrdp_orders_dest_blt((struct xrdp_orders*)session->orders, x, y, cx, cy, rop, rect); } /******************************************************************************/ int EXPORT_CC libxrdp_orders_line(struct xrdp_session* session, int mix_mode, int startx, int starty, int endx, int endy, int rop, int bg_color, struct xrdp_pen* pen, struct xrdp_rect* rect) { return xrdp_orders_line((struct xrdp_orders*)session->orders, mix_mode, startx, starty, endx, endy, rop, bg_color, pen, rect); } /******************************************************************************/ int EXPORT_CC libxrdp_orders_mem_blt(struct xrdp_session* session, int cache_id, int color_table, int x, int y, int cx, int cy, int rop, int srcx, int srcy, int cache_idx, struct xrdp_rect* rect) { return xrdp_orders_mem_blt((struct xrdp_orders*)session->orders, cache_id, color_table, x, y, cx, cy, rop, srcx, srcy, cache_idx, rect); } /******************************************************************************/ int EXPORT_CC libxrdp_orders_text(struct xrdp_session* session, int font, int flags, int mixmode, int fg_color, int bg_color, int clip_left, int clip_top, int clip_right, int clip_bottom, int box_left, int box_top, int box_right, int box_bottom, int x, int y, char* data, int data_len, struct xrdp_rect* rect) { return xrdp_orders_text((struct xrdp_orders*)session->orders, font, flags, mixmode, fg_color, bg_color, clip_left, clip_top, clip_right, clip_bottom, box_left, box_top, box_right, box_bottom, x, y, data, data_len, rect); } /******************************************************************************/ int EXPORT_CC libxrdp_orders_send_palette(struct xrdp_session* session, int* palette, int cache_id) { return xrdp_orders_send_palette((struct xrdp_orders*)session->orders, palette, cache_id); } /*****************************************************************************/ int EXPORT_CC libxrdp_orders_send_raw_bitmap(struct xrdp_session* session, int width, int height, int bpp, char* data, int cache_id, int cache_idx) { return xrdp_orders_send_raw_bitmap((struct xrdp_orders*)session->orders, width, height, bpp, data, cache_id, cache_idx); } /*****************************************************************************/ int EXPORT_CC libxrdp_orders_send_bitmap(struct xrdp_session* session, int width, int height, int bpp, char* data, int cache_id, int cache_idx) { return xrdp_orders_send_bitmap((struct xrdp_orders*)session->orders, width, height, bpp, data, cache_id, cache_idx); } /*****************************************************************************/ int EXPORT_CC libxrdp_orders_send_font(struct xrdp_session* session, struct xrdp_font_char* font_char, int font_index, int char_index) { return xrdp_orders_send_font((struct xrdp_orders*)session->orders, font_char, font_index, char_index); } /*****************************************************************************/ int EXPORT_CC libxrdp_reset(struct xrdp_session* session, int width, int height, int bpp) { if (session->client_info != 0) { /* older client can't resize */ if (session->client_info->build <= 419) { return 0; } /* if same, don't need to do anything */ if (session->client_info->width == width && session->client_info->height == height && session->client_info->bpp == bpp) { return 0; } session->client_info->width = width; session->client_info->height = height; session->client_info->bpp = bpp; } else { return 1; } /* this will send any lingering orders */ if (xrdp_orders_reset((struct xrdp_orders*)session->orders) != 0) { return 1; } /* shut down the rdp client */ if (xrdp_rdp_send_deactive((struct xrdp_rdp*)session->rdp) != 0) { return 1; } /* this should do the resizing */ if (xrdp_rdp_send_demand_active((struct xrdp_rdp*)session->rdp) != 0) { return 1; } /* process till up and running */ session->up_and_running = 0; libxrdp_process_data(session); return 0; } /*****************************************************************************/ int EXPORT_CC libxrdp_orders_send_raw_bitmap2(struct xrdp_session* session, int width, int height, int bpp, char* data, int cache_id, int cache_idx) { return xrdp_orders_send_raw_bitmap2((struct xrdp_orders*)session->orders, width, height, bpp, data, cache_id, cache_idx); } /*****************************************************************************/ int EXPORT_CC libxrdp_orders_send_bitmap2(struct xrdp_session* session, int width, int height, int bpp, char* data, int cache_id, int cache_idx) { return xrdp_orders_send_bitmap2((struct xrdp_orders*)session->orders, width, height, bpp, data, cache_id, cache_idx); } /*****************************************************************************/ /* returns error */ /* this function gets the channel name and its flags, index is zero based. either channel_name or channel_flags can be passed in nil if they are not needed */ int EXPORT_CC libxrdp_query_channel(struct xrdp_session* session, int index, char* channel_name, int* channel_flags) { int count = 0; struct xrdp_rdp* rdp = (struct xrdp_rdp *)NULL; struct xrdp_mcs* mcs = (struct xrdp_mcs *)NULL; struct mcs_channel_item* channel_item = (struct mcs_channel_item *)NULL; rdp = (struct xrdp_rdp*)session->rdp; mcs = rdp->sec_layer->mcs_layer; count = mcs->channel_list->count; if (index < 0 || index >= count) { return 1; } channel_item = (struct mcs_channel_item*) list_get_item(mcs->channel_list, index); if (channel_item == 0) { /* this should not happen */ return 1; } if (channel_name != 0) { g_strncpy(channel_name, channel_item->name, 8); } if (channel_flags != 0) { *channel_flags = channel_item->flags; } return 0; } /*****************************************************************************/ /* returns a zero based index of the channel, -1 if error or it dosen't exist */ int EXPORT_CC libxrdp_get_channel_id(struct xrdp_session* session, char* name) { int index = 0; int count = 0; struct xrdp_rdp* rdp = NULL; struct xrdp_mcs* mcs = NULL; struct mcs_channel_item* channel_item = NULL; rdp = (struct xrdp_rdp*)session->rdp; mcs = rdp->sec_layer->mcs_layer; count = mcs->channel_list->count; for (index = 0; index < count; index++) { channel_item = (struct mcs_channel_item*) list_get_item(mcs->channel_list, index); if (channel_item != 0) { if (g_strcasecmp(name, channel_item->name) == 0) { return index; } } } return -1; } /*****************************************************************************/ int EXPORT_CC libxrdp_send_to_channel(struct xrdp_session* session, int channel_id, char* data, int data_len, int total_data_len, int flags) { struct xrdp_rdp* rdp = NULL; struct xrdp_sec* sec = NULL; struct xrdp_channel* chan = NULL; struct stream* s = NULL; rdp = (struct xrdp_rdp*)session->rdp; sec = rdp->sec_layer; chan = sec->chan_layer; make_stream(s); init_stream(s, data_len + 1024); /* this should be big enough */ if (xrdp_channel_init(chan, s) != 0) { free_stream(s); return 1; } /* here we make a copy of the data */ out_uint8a(s, data, data_len); s_mark_end(s); if (xrdp_channel_send(chan, s, channel_id, total_data_len, flags) != 0) { free_stream(s); return 1; } free_stream(s); return 0; } /*****************************************************************************/ int EXPORT_CC libxrdp_orders_send_brush(struct xrdp_session* session, int width, int height, int bpp, int type, int size, char* data, int cache_id) { return xrdp_orders_send_brush((struct xrdp_orders*)session->orders, width, height, bpp, type, size, data, cache_id); } xrdp-0.6.0/libxrdp/libxrdp.h000066400000000000000000000266601203155130500157600ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2004-2010 libxrdp header */ #if !defined(LIBXRDP_H) #define LIBXRDP_H #if defined(HAVE_CONFIG_H) #include "config_ac.h" #endif #include "arch.h" #include "parse.h" #include "trans.h" #include "xrdp_constants.h" #include "defines.h" #include "os_calls.h" #include "ssl_calls.h" #include "list.h" #include "file.h" #include "libxrdpinc.h" #include "file_loc.h" /* tcp */ struct xrdp_tcp { struct trans* trans; struct xrdp_iso* iso_layer; /* owner */ }; /* iso */ struct xrdp_iso { struct xrdp_mcs* mcs_layer; /* owner */ struct xrdp_tcp* tcp_layer; }; /* used in mcs */ struct mcs_channel_item { char name[16]; int flags; int chanid; }; /* mcs */ struct xrdp_mcs { struct xrdp_sec* sec_layer; /* owner */ struct xrdp_iso* iso_layer; int userid; int chanid; struct stream* client_mcs_data; struct stream* server_mcs_data; struct list* channel_list; }; /* sec */ struct xrdp_sec { struct xrdp_rdp* rdp_layer; /* owner */ struct xrdp_mcs* mcs_layer; struct xrdp_channel* chan_layer; char server_random[32]; char client_random[64]; char client_crypt_random[72]; struct stream client_mcs_data; struct stream server_mcs_data; int decrypt_use_count; int encrypt_use_count; char decrypt_key[16]; char encrypt_key[16]; char decrypt_update_key[16]; char encrypt_update_key[16]; int rc4_key_size; /* 1 = 40 bit, 2 = 128 bit */ int rc4_key_len; /* 8 = 40 bit, 16 = 128 bit */ int crypt_level; /* 1, 2, 3 = low, meduim, high */ char sign_key[16]; void* decrypt_rc4_info; void* encrypt_rc4_info; char pub_exp[4]; char pub_mod[64]; char pub_sig[64]; char pri_exp[64]; int channel_code; }; /* channel */ struct xrdp_channel { struct xrdp_sec* sec_layer; struct xrdp_mcs* mcs_layer; }; /* rdp */ struct xrdp_rdp { struct xrdp_session* session; struct xrdp_sec* sec_layer; int share_id; int mcs_channel; struct xrdp_client_info client_info; }; /* state */ struct xrdp_orders_state { int last_order; /* last order sent */ int clip_left; /* RDP_ORDER_BOUNDS, RDP_ORDER_LASTBOUNDS */ int clip_top; int clip_right; int clip_bottom; int rect_x; /* RDP_ORDER_RECT */ int rect_y; int rect_cx; int rect_cy; int rect_color; int scr_blt_x; /* RDP_ORDER_SCREENBLT */ int scr_blt_y; int scr_blt_cx; int scr_blt_cy; int scr_blt_rop; int scr_blt_srcx; int scr_blt_srcy; int pat_blt_x; /* RDP_ORDER_PATBLT */ int pat_blt_y; int pat_blt_cx; int pat_blt_cy; int pat_blt_rop; int pat_blt_bg_color; int pat_blt_fg_color; struct xrdp_brush pat_blt_brush; int dest_blt_x; /* RDP_ORDER_DESTBLT */ int dest_blt_y; int dest_blt_cx; int dest_blt_cy; int dest_blt_rop; int line_mix_mode; /* RDP_ORDER_LINE */ int line_startx; int line_starty; int line_endx; int line_endy; int line_bg_color; int line_rop; struct xrdp_pen line_pen; int mem_blt_color_table; /* RDP_ORDER_MEMBLT */ int mem_blt_cache_id; int mem_blt_x; int mem_blt_y; int mem_blt_cx; int mem_blt_cy; int mem_blt_rop; int mem_blt_srcx; int mem_blt_srcy; int mem_blt_cache_idx; int text_font; /* RDP_ORDER_TEXT2 */ int text_flags; int text_unknown; int text_mixmode; int text_fg_color; int text_bg_color; int text_clip_left; int text_clip_top; int text_clip_right; int text_clip_bottom; int text_box_left; int text_box_top; int text_box_right; int text_box_bottom; int text_x; int text_y; int text_len; char* text_data; }; /* orders */ struct xrdp_orders { struct stream* out_s; struct xrdp_rdp* rdp_layer; struct xrdp_session* session; struct xrdp_wm* wm; char* order_count_ptr; /* pointer to count, set when sending */ int order_count; int order_level; /* inc for every call to xrdp_orders_init */ struct xrdp_orders_state orders_state; }; /* xrdp_tcp.c */ struct xrdp_tcp* APP_CC xrdp_tcp_create(struct xrdp_iso* owner, struct trans* trans); void APP_CC xrdp_tcp_delete(struct xrdp_tcp* self); int APP_CC xrdp_tcp_init(struct xrdp_tcp* self, struct stream* s); int APP_CC xrdp_tcp_recv(struct xrdp_tcp* self, struct stream* s, int len); int APP_CC xrdp_tcp_send(struct xrdp_tcp* self, struct stream* s); /* xrdp_iso.c */ struct xrdp_iso* APP_CC xrdp_iso_create(struct xrdp_mcs* owner, struct trans* trans); void APP_CC xrdp_iso_delete(struct xrdp_iso* self); int APP_CC xrdp_iso_init(struct xrdp_iso* self, struct stream* s); int APP_CC xrdp_iso_recv(struct xrdp_iso* self, struct stream* s); int APP_CC xrdp_iso_send(struct xrdp_iso* self, struct stream* s); int APP_CC xrdp_iso_incoming(struct xrdp_iso* self); /* xrdp_mcs.c */ struct xrdp_mcs* APP_CC xrdp_mcs_create(struct xrdp_sec* owner, struct trans* trans, struct stream* client_mcs_data, struct stream* server_mcs_data); void APP_CC xrdp_mcs_delete(struct xrdp_mcs* self); int APP_CC xrdp_mcs_init(struct xrdp_mcs* self, struct stream* s); int APP_CC xrdp_mcs_recv(struct xrdp_mcs* self, struct stream* s, int* chan); int APP_CC xrdp_mcs_send(struct xrdp_mcs* self, struct stream* s, int chan); int APP_CC xrdp_mcs_incoming(struct xrdp_mcs* self); int APP_CC xrdp_mcs_disconnect(struct xrdp_mcs* self); /* xrdp_sec.c */ struct xrdp_sec* APP_CC xrdp_sec_create(struct xrdp_rdp* owner, struct trans* trans, int crypt_level, int channel_code); void APP_CC xrdp_sec_delete(struct xrdp_sec* self); int APP_CC xrdp_sec_init(struct xrdp_sec* self, struct stream* s); int APP_CC xrdp_sec_recv(struct xrdp_sec* self, struct stream* s, int* chan); int APP_CC xrdp_sec_send(struct xrdp_sec* self, struct stream* s, int chan); int APP_CC xrdp_sec_process_mcs_data(struct xrdp_sec* self); int APP_CC xrdp_sec_out_mcs_data(struct xrdp_sec* self); int APP_CC xrdp_sec_incoming(struct xrdp_sec* self); int APP_CC xrdp_sec_disconnect(struct xrdp_sec* self); /* xrdp_rdp.c */ struct xrdp_rdp* APP_CC xrdp_rdp_create(struct xrdp_session* session, struct trans* trans); void APP_CC xrdp_rdp_delete(struct xrdp_rdp* self); int APP_CC xrdp_rdp_init(struct xrdp_rdp* self, struct stream* s); int APP_CC xrdp_rdp_init_data(struct xrdp_rdp* self, struct stream* s); int APP_CC xrdp_rdp_recv(struct xrdp_rdp* self, struct stream* s, int* code); int APP_CC xrdp_rdp_send(struct xrdp_rdp* self, struct stream* s, int pdu_type); int APP_CC xrdp_rdp_send_data(struct xrdp_rdp* self, struct stream* s, int data_pdu_type); int APP_CC xrdp_rdp_send_data_update_sync(struct xrdp_rdp* self); int APP_CC xrdp_rdp_incoming(struct xrdp_rdp* self); int APP_CC xrdp_rdp_send_demand_active(struct xrdp_rdp* self); int APP_CC xrdp_rdp_process_confirm_active(struct xrdp_rdp* self, struct stream* s); int APP_CC xrdp_rdp_process_data(struct xrdp_rdp* self, struct stream* s); int APP_CC xrdp_rdp_disconnect(struct xrdp_rdp* self); int APP_CC xrdp_rdp_send_deactive(struct xrdp_rdp* self); /* xrdp_orders.c */ struct xrdp_orders* APP_CC xrdp_orders_create(struct xrdp_session* session, struct xrdp_rdp* rdp_layer); void APP_CC xrdp_orders_delete(struct xrdp_orders* self); int APP_CC xrdp_orders_reset(struct xrdp_orders* self); int APP_CC xrdp_orders_init(struct xrdp_orders* self); int APP_CC xrdp_orders_send(struct xrdp_orders* self); int APP_CC xrdp_orders_force_send(struct xrdp_orders* self); int APP_CC xrdp_orders_rect(struct xrdp_orders* self, int x, int y, int cx, int cy, int color, struct xrdp_rect* rect); int APP_CC xrdp_orders_screen_blt(struct xrdp_orders* self, int x, int y, int cx, int cy, int srcx, int srcy, int rop, struct xrdp_rect* rect); int APP_CC xrdp_orders_pat_blt(struct xrdp_orders* self, int x, int y, int cx, int cy, int rop, int bg_color, int fg_color, struct xrdp_brush* brush, struct xrdp_rect* rect); int APP_CC xrdp_orders_dest_blt(struct xrdp_orders* self, int x, int y, int cx, int cy, int rop, struct xrdp_rect* rect); int APP_CC xrdp_orders_line(struct xrdp_orders* self, int mix_mode, int startx, int starty, int endx, int endy, int rop, int bg_color, struct xrdp_pen* pen, struct xrdp_rect* rect); int APP_CC xrdp_orders_mem_blt(struct xrdp_orders* self, int cache_id, int color_table, int x, int y, int cx, int cy, int rop, int srcx, int srcy, int cache_idx, struct xrdp_rect* rect); int APP_CC xrdp_orders_text(struct xrdp_orders* self, int font, int flags, int mixmode, int fg_color, int bg_color, int clip_left, int clip_top, int clip_right, int clip_bottom, int box_left, int box_top, int box_right, int box_bottom, int x, int y, char* data, int data_len, struct xrdp_rect* rect); int APP_CC xrdp_orders_send_palette(struct xrdp_orders* self, int* palette, int cache_id); int APP_CC xrdp_orders_send_raw_bitmap(struct xrdp_orders* self, int width, int height, int bpp, char* data, int cache_id, int cache_idx); int APP_CC xrdp_orders_send_bitmap(struct xrdp_orders* self, int width, int height, int bpp, char* data, int cache_id, int cache_idx); int APP_CC xrdp_orders_send_font(struct xrdp_orders* self, struct xrdp_font_char* font_char, int font_index, int char_index); int APP_CC xrdp_orders_send_raw_bitmap2(struct xrdp_orders* self, int width, int height, int bpp, char* data, int cache_id, int cache_idx); int APP_CC xrdp_orders_send_bitmap2(struct xrdp_orders* self, int width, int height, int bpp, char* data, int cache_id, int cache_idx); int APP_CC xrdp_orders_send_brush(struct xrdp_orders* self, int width, int height, int bpp, int type, int size, char* data, int cache_id); /* xrdp_bitmap_compress.c */ int APP_CC xrdp_bitmap_compress(char* in_data, int width, int height, struct stream* s, int bpp, int byte_limit, int start_line, struct stream* temp, int e); /* xrdp_channel.c */ struct xrdp_channel* APP_CC xrdp_channel_create(struct xrdp_sec* owner, struct xrdp_mcs* mcs_layer); void APP_CC xrdp_channel_delete(struct xrdp_channel* self); int APP_CC xrdp_channel_init(struct xrdp_channel* self, struct stream* s); int APP_CC xrdp_channel_send(struct xrdp_channel* self, struct stream* s, int channel_id, int total_data_len, int flags); int APP_CC xrdp_channel_process(struct xrdp_channel* self, struct stream* s, int chanid); #endif xrdp-0.6.0/libxrdp/libxrdpinc.h000066400000000000000000000164301203155130500164440ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2004-2010 header file for use with libxrdp.so / xrdp.dll */ #ifndef LIBXRDPINC_H #define LIBXRDPINC_H struct xrdp_client_info { int bpp; int width; int height; /* bitmap cache info */ int cache1_entries; int cache1_size; int cache2_entries; int cache2_size; int cache3_entries; int cache3_size; int bitmap_cache_persist_enable; /* 0 or 2 */ int bitmap_cache_version; /* 0 = original version, 2 = v2 */ /* pointer info */ int pointer_cache_entries; /* other */ int use_bitmap_comp; int use_bitmap_cache; int op1; /* use smaller bitmap header, non cache */ int op2; /* use smaller bitmap header in bitmap cache */ int desktop_cache; int use_compact_packets; /* rdp5 smaller packets */ char hostname[32]; int build; int keylayout; char username[256]; char password[256]; char domain[256]; char program[256]; char directory[256]; int rdp_compression; int rdp_autologin; int crypt_level; /* 1, 2, 3 = low, medium, high */ int channel_code; /* 0 = no channels 1 = channels */ int sound_code; /* 1 = leave sound at server */ int is_mce; int rdp5_performanceflags; int brush_cache_code; /* 0 = no cache 1 = 8x8 standard cache 2 = arbitrary dimensions */ char client_ip[256]; int max_bpp; }; struct xrdp_brush { int x_orgin; int y_orgin; int style; char pattern[8]; }; struct xrdp_pen { int style; int width; int color; }; struct xrdp_font_char { int offset; int baseline; int width; int height; int incby; char* data; }; struct xrdp_rect { int left; int top; int right; int bottom; }; struct xrdp_session { long id; struct trans* trans; int (*callback)(long id, int msg, long param1, long param2, long param3, long param4); void* rdp; void* orders; struct xrdp_client_info* client_info; int up_and_running; struct stream* s; int (*is_term)(void); }; struct xrdp_session* DEFAULT_CC libxrdp_init(tbus id, struct trans* trans); int DEFAULT_CC libxrdp_exit(struct xrdp_session* session); int DEFAULT_CC libxrdp_disconnect(struct xrdp_session* session); int DEFAULT_CC libxrdp_process_incomming(struct xrdp_session* session); int DEFAULT_CC libxrdp_process_data(struct xrdp_session* session); int DEFAULT_CC libxrdp_send_palette(struct xrdp_session* session, int* palette); int DEFAULT_CC libxrdp_send_bell(struct xrdp_session* session); int DEFAULT_CC libxrdp_send_bitmap(struct xrdp_session* session, int width, int height, int bpp, char* data, int x, int y, int cx, int cy); int DEFAULT_CC libxrdp_send_pointer(struct xrdp_session* session, int cache_idx, char* data, char* mask, int x, int y); int DEFAULT_CC libxrdp_set_pointer(struct xrdp_session* session, int cache_idx); int DEFAULT_CC libxrdp_orders_init(struct xrdp_session* session); int DEFAULT_CC libxrdp_orders_send(struct xrdp_session* session); int DEFAULT_CC libxrdp_orders_force_send(struct xrdp_session* session); int DEFAULT_CC libxrdp_orders_rect(struct xrdp_session* session, int x, int y, int cx, int cy, int color, struct xrdp_rect* rect); int DEFAULT_CC libxrdp_orders_screen_blt(struct xrdp_session* session, int x, int y, int cx, int cy, int srcx, int srcy, int rop, struct xrdp_rect* rect); int DEFAULT_CC libxrdp_orders_pat_blt(struct xrdp_session* session, int x, int y, int cx, int cy, int rop, int bg_color, int fg_color, struct xrdp_brush* brush, struct xrdp_rect* rect); int DEFAULT_CC libxrdp_orders_dest_blt(struct xrdp_session* session, int x, int y, int cx, int cy, int rop, struct xrdp_rect* rect); int DEFAULT_CC libxrdp_orders_line(struct xrdp_session* session, int mix_mode, int startx, int starty, int endx, int endy, int rop, int bg_color, struct xrdp_pen* pen, struct xrdp_rect* rect); int DEFAULT_CC libxrdp_orders_mem_blt(struct xrdp_session* session, int cache_id, int color_table, int x, int y, int cx, int cy, int rop, int srcx, int srcy, int cache_idx, struct xrdp_rect* rect); int DEFAULT_CC libxrdp_orders_text(struct xrdp_session* session, int font, int flags, int mixmode, int fg_color, int bg_color, int clip_left, int clip_top, int clip_right, int clip_bottom, int box_left, int box_top, int box_right, int box_bottom, int x, int y, char* data, int data_len, struct xrdp_rect* rect); int DEFAULT_CC libxrdp_orders_send_palette(struct xrdp_session* session, int* palette, int cache_id); int DEFAULT_CC libxrdp_orders_send_raw_bitmap(struct xrdp_session* session, int width, int height, int bpp, char* data, int cache_id, int cache_idx); int DEFAULT_CC libxrdp_orders_send_bitmap(struct xrdp_session* session, int width, int height, int bpp, char* data, int cache_id, int cache_idx); int DEFAULT_CC libxrdp_orders_send_font(struct xrdp_session* session, struct xrdp_font_char* font_char, int font_index, int char_index); int DEFAULT_CC libxrdp_reset(struct xrdp_session* session, int width, int height, int bpp); int DEFAULT_CC libxrdp_orders_send_raw_bitmap2(struct xrdp_session* session, int width, int height, int bpp, char* data, int cache_id, int cache_idx); int DEFAULT_CC libxrdp_orders_send_bitmap2(struct xrdp_session* session, int width, int height, int bpp, char* data, int cache_id, int cache_idx); int DEFAULT_CC libxrdp_query_channel(struct xrdp_session* session, int index, char* channel_name, int* channel_flags); int DEFAULT_CC libxrdp_get_channel_id(struct xrdp_session* session, char* name); int DEFAULT_CC libxrdp_send_to_channel(struct xrdp_session* session, int channel_id, char* data, int data_len, int total_data_len, int flags); int DEFAULT_CC libxrdp_orders_send_brush(struct xrdp_session* session, int width, int height, int bpp, int type, int size, char* data, int cache_id); #endif xrdp-0.6.0/libxrdp/xrdp_bitmap_compress.c000066400000000000000000001154751203155130500205360ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2004-2010 bitmap compressor */ #include "libxrdp.h" /*****************************************************************************/ #define IN_PIXEL8(in_ptr, in_x, in_y, in_w, in_last_pixel, in_pixel); \ { \ if (in_ptr == 0) \ { \ in_pixel = 0; \ } \ else if (in_x < in_w) \ { \ in_pixel = GETPIXEL8(in_ptr, in_x, in_y, in_w); \ } \ else \ { \ in_pixel = in_last_pixel; \ } \ } /*****************************************************************************/ #define IN_PIXEL16(in_ptr, in_x, in_y, in_w, in_last_pixel, in_pixel); \ { \ if (in_ptr == 0) \ { \ in_pixel = 0; \ } \ else if (in_x < in_w) \ { \ in_pixel = GETPIXEL16(in_ptr, in_x, in_y, in_w); \ } \ else \ { \ in_pixel = in_last_pixel; \ } \ } /*****************************************************************************/ #define IN_PIXEL32(in_ptr, in_x, in_y, in_w, in_last_pixel, in_pixel); \ { \ if (in_ptr == 0) \ { \ in_pixel = 0; \ } \ else if (in_x < in_w) \ { \ in_pixel = GETPIXEL32(in_ptr, in_x, in_y, in_w); \ } \ else \ { \ in_pixel = in_last_pixel; \ } \ } /*****************************************************************************/ /* color */ #define OUT_COLOR_COUNT1(in_count, in_s, in_data) \ { \ if (in_count > 0) \ { \ if (in_count < 32) \ { \ temp = (0x3 << 5) | in_count; \ out_uint8(in_s, temp); \ out_uint8(in_s, in_data); \ } \ else if (in_count < 256 + 32) \ { \ out_uint8(in_s, 0x60); \ temp = in_count - 32; \ out_uint8(in_s, temp); \ out_uint8(in_s, in_data); \ } \ else \ { \ out_uint8(in_s, 0xf3); \ out_uint16_le(in_s, in_count); \ out_uint8(in_s, in_data); \ } \ } \ in_count = 0; \ } /*****************************************************************************/ /* color */ #define OUT_COLOR_COUNT2(in_count, in_s, in_data) \ { \ if (in_count > 0) \ { \ if (in_count < 32) \ { \ temp = (0x3 << 5) | in_count; \ out_uint8(in_s, temp); \ out_uint16_le(in_s, in_data); \ } \ else if (in_count < 256 + 32) \ { \ out_uint8(in_s, 0x60); \ temp = in_count - 32; \ out_uint8(in_s, temp); \ out_uint16_le(in_s, in_data); \ } \ else \ { \ out_uint8(in_s, 0xf3); \ out_uint16_le(in_s, in_count); \ out_uint16_le(in_s, in_data); \ } \ } \ in_count = 0; \ } /*****************************************************************************/ /* color */ #define OUT_COLOR_COUNT3(in_count, in_s, in_data) \ { \ if (in_count > 0) \ { \ if (in_count < 32) \ { \ temp = (0x3 << 5) | in_count; \ out_uint8(in_s, temp); \ out_uint8(in_s, in_data & 0xff); \ out_uint8(in_s, (in_data >> 8) & 0xff); \ out_uint8(in_s, (in_data >> 16) & 0xff); \ } \ else if (in_count < 256 + 32) \ { \ out_uint8(in_s, 0x60); \ temp = in_count - 32; \ out_uint8(in_s, temp); \ out_uint8(in_s, in_data & 0xff); \ out_uint8(in_s, (in_data >> 8) & 0xff); \ out_uint8(in_s, (in_data >> 16) & 0xff); \ } \ else \ { \ out_uint8(in_s, 0xf3); \ out_uint16_le(in_s, in_count); \ out_uint8(in_s, in_data & 0xff); \ out_uint8(in_s, (in_data >> 8) & 0xff); \ out_uint8(in_s, (in_data >> 16) & 0xff); \ } \ } \ in_count = 0; \ } /*****************************************************************************/ /* copy */ #define OUT_COPY_COUNT1(in_count, in_s, in_data) \ { \ if (in_count > 0) \ { \ if (in_count < 32) \ { \ temp = (0x4 << 5) | in_count; \ out_uint8(in_s, temp); \ out_uint8a(in_s, in_data->data, in_count); \ } \ else if (in_count < 256 + 32) \ { \ out_uint8(in_s, 0x80); \ temp = in_count - 32; \ out_uint8(in_s, temp); \ out_uint8a(in_s, in_data->data, in_count); \ } \ else \ { \ out_uint8(in_s, 0xf4); \ out_uint16_le(in_s, in_count); \ out_uint8a(in_s, in_data->data, in_count); \ } \ } \ in_count = 0; \ init_stream(in_data, 0); \ } /*****************************************************************************/ /* copy */ #define OUT_COPY_COUNT2(in_count, in_s, in_data) \ { \ if (in_count > 0) \ { \ if (in_count < 32) \ { \ temp = (0x4 << 5) | in_count; \ out_uint8(in_s, temp); \ temp = in_count * 2; \ out_uint8a(in_s, in_data->data, temp); \ } \ else if (in_count < 256 + 32) \ { \ out_uint8(in_s, 0x80); \ temp = in_count - 32; \ out_uint8(in_s, temp); \ temp = in_count * 2; \ out_uint8a(in_s, in_data->data, temp); \ } \ else \ { \ out_uint8(in_s, 0xf4); \ out_uint16_le(in_s, in_count); \ temp = in_count * 2; \ out_uint8a(in_s, in_data->data, temp); \ } \ } \ in_count = 0; \ init_stream(in_data, 0); \ } /*****************************************************************************/ /* copy */ #define OUT_COPY_COUNT3(in_count, in_s, in_data) \ { \ if (in_count > 0) \ { \ if (in_count < 32) \ { \ temp = (0x4 << 5) | in_count; \ out_uint8(in_s, temp); \ temp = in_count * 3; \ out_uint8a(in_s, in_data->end, temp); \ } \ else if (in_count < 256 + 32) \ { \ out_uint8(in_s, 0x80); \ temp = in_count - 32; \ out_uint8(in_s, temp); \ temp = in_count * 3; \ out_uint8a(in_s, in_data->end, temp); \ } \ else \ { \ out_uint8(in_s, 0xf4); \ out_uint16_le(in_s, in_count); \ temp = in_count * 3; \ out_uint8a(in_s, in_data->end, temp); \ } \ } \ in_count = 0; \ init_stream(in_data, 0); \ } /*****************************************************************************/ /* bicolor */ #define OUT_BICOLOR_COUNT1(in_count, in_s, in_color1, in_color2) \ { \ if (in_count > 0) \ { \ if (in_count / 2 < 16) \ { \ temp = (0xe << 4) | (in_count / 2); \ out_uint8(in_s, temp); \ out_uint8(in_s, in_color1); \ out_uint8(in_s, in_color2); \ } \ else if (in_count / 2 < 256 + 16) \ { \ out_uint8(in_s, 0xe0); \ temp = in_count / 2 - 16; \ out_uint8(in_s, temp); \ out_uint8(in_s, in_color1); \ out_uint8(in_s, in_color2); \ } \ else \ { \ out_uint8(in_s, 0xf8); \ temp = in_count / 2; \ out_uint16_le(in_s, temp); \ out_uint8(in_s, in_color1); \ out_uint8(in_s, in_color2); \ } \ } \ in_count = 0; \ } /*****************************************************************************/ /* bicolor */ #define OUT_BICOLOR_COUNT2(in_count, in_s, in_color1, in_color2) \ { \ if (in_count > 0) \ { \ if (in_count / 2 < 16) \ { \ temp = (0xe << 4) | (in_count / 2); \ out_uint8(in_s, temp); \ out_uint16_le(in_s, in_color1); \ out_uint16_le(in_s, in_color2); \ } \ else if (in_count / 2 < 256 + 16) \ { \ out_uint8(in_s, 0xe0); \ temp = in_count / 2 - 16; \ out_uint8(in_s, temp); \ out_uint16_le(in_s, in_color1); \ out_uint16_le(in_s, in_color2); \ } \ else \ { \ out_uint8(in_s, 0xf8); \ temp = in_count / 2; \ out_uint16_le(in_s, temp); \ out_uint16_le(in_s, in_color1); \ out_uint16_le(in_s, in_color2); \ } \ } \ in_count = 0; \ } /*****************************************************************************/ /* bicolor */ #define OUT_BICOLOR_COUNT3(in_count, in_s, in_color1, in_color2) \ { \ if (in_count > 0) \ { \ if (in_count / 2 < 16) \ { \ temp = (0xe << 4) | (in_count / 2); \ out_uint8(in_s, temp); \ out_uint8(in_s, in_color1 & 0xff); \ out_uint8(in_s, (in_color1 >> 8) & 0xff); \ out_uint8(in_s, (in_color1 >> 16) & 0xff); \ out_uint8(in_s, in_color2 & 0xff); \ out_uint8(in_s, (in_color2 >> 8) & 0xff); \ out_uint8(in_s, (in_color2 >> 16) & 0xff); \ } \ else if (in_count / 2 < 256 + 16) \ { \ out_uint8(in_s, 0xe0); \ temp = in_count / 2 - 16; \ out_uint8(in_s, temp); \ out_uint8(in_s, in_color1 & 0xff); \ out_uint8(in_s, (in_color1 >> 8) & 0xff); \ out_uint8(in_s, (in_color1 >> 16) & 0xff); \ out_uint8(in_s, in_color2 & 0xff); \ out_uint8(in_s, (in_color2 >> 8) & 0xff); \ out_uint8(in_s, (in_color2 >> 16) & 0xff); \ } \ else \ { \ out_uint8(in_s, 0xf8); \ temp = in_count / 2; \ out_uint16_le(in_s, temp); \ out_uint8(in_s, in_color1 & 0xff); \ out_uint8(in_s, (in_color1 >> 8) & 0xff); \ out_uint8(in_s, (in_color1 >> 16) & 0xff); \ out_uint8(in_s, in_color2 & 0xff); \ out_uint8(in_s, (in_color2 >> 8) & 0xff); \ out_uint8(in_s, (in_color2 >> 16) & 0xff); \ } \ } \ in_count = 0; \ } /*****************************************************************************/ /* fill */ #define OUT_FILL_COUNT1(in_count, in_s) \ { \ if (in_count > 0) \ { \ if (in_count < 32) \ { \ out_uint8(in_s, in_count); \ } \ else if (in_count < 256 + 32) \ { \ out_uint8(in_s, 0x0); \ temp = in_count - 32; \ out_uint8(in_s, temp); \ } \ else \ { \ out_uint8(in_s, 0xf0); \ out_uint16_le(in_s, in_count); \ } \ } \ in_count = 0; \ } /*****************************************************************************/ /* fill */ #define OUT_FILL_COUNT2(in_count, in_s) \ { \ if (in_count > 0) \ { \ if (in_count < 32) \ { \ out_uint8(in_s, in_count); \ } \ else if (in_count < 256 + 32) \ { \ out_uint8(in_s, 0x0); \ temp = in_count - 32; \ out_uint8(in_s, temp); \ } \ else \ { \ out_uint8(in_s, 0xf0); \ out_uint16_le(in_s, in_count); \ } \ } \ in_count = 0; \ } /*****************************************************************************/ /* fill */ #define OUT_FILL_COUNT3(in_count, in_s) \ { \ if (in_count > 0) \ { \ if (in_count < 32) \ { \ out_uint8(in_s, in_count); \ } \ else if (in_count < 256 + 32) \ { \ out_uint8(in_s, 0x0); \ temp = in_count - 32; \ out_uint8(in_s, temp); \ } \ else \ { \ out_uint8(in_s, 0xf0); \ out_uint16_le(in_s, in_count); \ } \ } \ in_count = 0; \ } /*****************************************************************************/ /* mix */ #define OUT_MIX_COUNT1(in_count, in_s) \ { \ if (in_count > 0) \ { \ if (in_count < 32) \ { \ temp = (0x1 << 5) | in_count; \ out_uint8(in_s, temp); \ } \ else if (in_count < 256 + 32) \ { \ out_uint8(in_s, 0x20); \ temp = in_count - 32; \ out_uint8(in_s, temp); \ } \ else \ { \ out_uint8(in_s, 0xf1); \ out_uint16_le(in_s, in_count); \ } \ } \ in_count = 0; \ } /*****************************************************************************/ /* mix */ #define OUT_MIX_COUNT2(in_count, in_s) \ { \ if (in_count > 0) \ { \ if (in_count < 32) \ { \ temp = (0x1 << 5) | in_count; \ out_uint8(in_s, temp); \ } \ else if (in_count < 256 + 32) \ { \ out_uint8(in_s, 0x20); \ temp = in_count - 32; \ out_uint8(in_s, temp); \ } \ else \ { \ out_uint8(in_s, 0xf1); \ out_uint16_le(in_s, in_count); \ } \ } \ in_count = 0; \ } /*****************************************************************************/ /* mix */ #define OUT_MIX_COUNT3(in_count, in_s) \ { \ if (in_count > 0) \ { \ if (in_count < 32) \ { \ temp = (0x1 << 5) | in_count; \ out_uint8(in_s, temp); \ } \ else if (in_count < 256 + 32) \ { \ out_uint8(in_s, 0x20); \ temp = in_count - 32; \ out_uint8(in_s, temp); \ } \ else \ { \ out_uint8(in_s, 0xf1); \ out_uint16_le(in_s, in_count); \ } \ } \ in_count = 0; \ } /*****************************************************************************/ /* fom */ #define OUT_FOM_COUNT1(in_count, in_s, in_mask, in_mask_len) \ { \ if (in_count > 0) \ { \ if ((in_count % 8) == 0 && in_count < 249) \ { \ temp = (0x2 << 5) | (in_count / 8); \ out_uint8(in_s, temp); \ out_uint8a(in_s, in_mask, in_mask_len); \ } \ else if (in_count < 256) \ { \ out_uint8(in_s, 0x40); \ temp = in_count - 1; \ out_uint8(in_s, temp); \ out_uint8a(in_s, in_mask, in_mask_len); \ } \ else \ { \ out_uint8(in_s, 0xf2); \ out_uint16_le(in_s, in_count); \ out_uint8a(in_s, in_mask, in_mask_len); \ } \ } \ in_count = 0; \ } /*****************************************************************************/ /* fom */ #define OUT_FOM_COUNT2(in_count, in_s, in_mask, in_mask_len) \ { \ if (in_count > 0) \ { \ if ((in_count % 8) == 0 && in_count < 249) \ { \ temp = (0x2 << 5) | (in_count / 8); \ out_uint8(in_s, temp); \ out_uint8a(in_s, in_mask, in_mask_len); \ } \ else if (in_count < 256) \ { \ out_uint8(in_s, 0x40); \ temp = in_count - 1; \ out_uint8(in_s, temp); \ out_uint8a(in_s, in_mask, in_mask_len); \ } \ else \ { \ out_uint8(in_s, 0xf2); \ out_uint16_le(in_s, in_count); \ out_uint8a(in_s, in_mask, in_mask_len); \ } \ } \ in_count = 0; \ } /*****************************************************************************/ /* fill or mix (fom) */ #define OUT_FOM_COUNT3(in_count, in_s, in_mask, in_mask_len) \ { \ if (in_count > 0) \ { \ if ((in_count % 8) == 0 && in_count < 249) \ { \ temp = (0x2 << 5) | (in_count / 8); \ out_uint8(in_s, temp); \ out_uint8a(in_s, in_mask, in_mask_len); \ } \ else if (in_count < 256) \ { \ out_uint8(in_s, 0x40); \ temp = in_count - 1; \ out_uint8(in_s, temp); \ out_uint8a(in_s, in_mask, in_mask_len); \ } \ else \ { \ out_uint8(in_s, 0xf2); \ out_uint16_le(in_s, in_count); \ out_uint8a(in_s, in_mask, in_mask_len); \ } \ } \ in_count = 0; \ } /*****************************************************************************/ #define TEST_FILL \ ((last_line == 0 && pixel == 0) || \ (last_line != 0 && pixel == ypixel)) #define TEST_MIX \ ((last_line == 0 && pixel == mix) || \ (last_line != 0 && pixel == (ypixel ^ mix))) #define TEST_FOM (TEST_FILL || TEST_MIX) #define TEST_COLOR (pixel == last_pixel) #define TEST_BICOLOR \ ( \ (pixel != last_pixel) && \ ( \ (!bicolor_spin && pixel == bicolor1 && last_pixel == bicolor2) || \ (bicolor_spin && pixel == bicolor2 && last_pixel == bicolor1) \ ) \ ) #define RESET_COUNTS \ { \ bicolor_count = 0; \ fill_count = 0; \ color_count = 0; \ mix_count = 0; \ fom_count = 0; \ fom_mask_len = 0; \ bicolor_spin = 0; \ } /*****************************************************************************/ int APP_CC xrdp_bitmap_compress(char* in_data, int width, int height, struct stream* s, int bpp, int byte_limit, int start_line, struct stream* temp_s, int e) { char* line; char* last_line; char fom_mask[8192]; /* good for up to 64K bitmap */ int lines_sent; int pixel; int count; int color_count; int last_pixel; int bicolor_count; int bicolor1; int bicolor2; int bicolor_spin; int end; int i; int out_count; int ypixel; int last_ypixel; int fill_count; int mix_count; int mix; int fom_count; int fom_mask_len; int temp; /* used in macros */ init_stream(temp_s, 0); fom_mask_len = 0; last_line = 0; lines_sent = 0; end = width + e; count = 0; color_count = 0; last_pixel = 0; last_ypixel = 0; bicolor_count = 0; bicolor1 = 0; bicolor2 = 0; bicolor_spin = 0; fill_count = 0; mix_count = 0; fom_count = 0; if (bpp == 8) { mix = 0xff; out_count = end; line = in_data + width * start_line; while (start_line >= 0 && out_count < 32768) { i = (s->p - s->data) + count; if (i - color_count >= byte_limit && i - bicolor_count >= byte_limit && i - fill_count >= byte_limit && i - mix_count >= byte_limit && i - fom_count >= byte_limit) { break; } out_count += end; for (i = 0; i < end; i++) { /* read next pixel */ IN_PIXEL8(line, i, 0, width, last_pixel, pixel); IN_PIXEL8(last_line, i, 0, width, last_ypixel, ypixel); if (!TEST_FILL) { if (fill_count > 3 && fill_count >= color_count && fill_count >= bicolor_count && fill_count >= mix_count && fill_count >= fom_count) { count -= fill_count; OUT_COPY_COUNT1(count, s, temp_s); OUT_FILL_COUNT1(fill_count, s); RESET_COUNTS; } fill_count = 0; } if (!TEST_MIX) { if (mix_count > 3 && mix_count >= fill_count && mix_count >= bicolor_count && mix_count >= color_count && mix_count >= fom_count) { count -= mix_count; OUT_COPY_COUNT1(count, s, temp_s); OUT_MIX_COUNT1(mix_count, s); RESET_COUNTS; } mix_count = 0; } if (!TEST_COLOR) { if (color_count > 3 && color_count >= fill_count && color_count >= bicolor_count && color_count >= mix_count && color_count >= fom_count) { count -= color_count; OUT_COPY_COUNT1(count, s, temp_s); OUT_COLOR_COUNT1(color_count, s, last_pixel); RESET_COUNTS; } color_count = 0; } if (!TEST_BICOLOR) { if (bicolor_count > 3 && bicolor_count >= fill_count && bicolor_count >= color_count && bicolor_count >= mix_count && bicolor_count >= fom_count) { if ((bicolor_count % 2) == 0) { count -= bicolor_count; OUT_COPY_COUNT1(count, s, temp_s); OUT_BICOLOR_COUNT1(bicolor_count, s, bicolor1, bicolor2); } else { bicolor_count--; count -= bicolor_count; OUT_COPY_COUNT1(count, s, temp_s); OUT_BICOLOR_COUNT1(bicolor_count, s, bicolor2, bicolor1); } RESET_COUNTS; } bicolor_count = 0; bicolor1 = last_pixel; bicolor2 = pixel; bicolor_spin = 0; } if (!TEST_FOM) { if (fom_count > 3 && fom_count >= fill_count && fom_count >= color_count && fom_count >= mix_count && fom_count >= bicolor_count) { count -= fom_count; OUT_COPY_COUNT1(count, s, temp_s); OUT_FOM_COUNT1(fom_count, s, fom_mask, fom_mask_len); RESET_COUNTS; } fom_count = 0; fom_mask_len = 0; } if (TEST_FILL) { fill_count++; } if (TEST_MIX) { mix_count++; } if (TEST_COLOR) { color_count++; } if (TEST_BICOLOR) { bicolor_spin = !bicolor_spin; bicolor_count++; } if (TEST_FOM) { if ((fom_count % 8) == 0) { fom_mask[fom_mask_len] = 0; fom_mask_len++; } if (pixel == (ypixel ^ mix)) { fom_mask[fom_mask_len - 1] |= (1 << (fom_count % 8)); } fom_count++; } out_uint8(temp_s, pixel); count++; last_pixel = pixel; last_ypixel = ypixel; } /* can't take fix, mix, or fom past first line */ if (last_line == 0) { if (fill_count > 3 && fill_count >= color_count && fill_count >= bicolor_count && fill_count >= mix_count && fill_count >= fom_count) { count -= fill_count; OUT_COPY_COUNT1(count, s, temp_s); OUT_FILL_COUNT1(fill_count, s); RESET_COUNTS; } fill_count = 0; if (mix_count > 3 && mix_count >= fill_count && mix_count >= bicolor_count && mix_count >= color_count && mix_count >= fom_count) { count -= mix_count; OUT_COPY_COUNT1(count, s, temp_s); OUT_MIX_COUNT1(mix_count, s); RESET_COUNTS; } mix_count = 0; if (fom_count > 3 && fom_count >= fill_count && fom_count >= color_count && fom_count >= mix_count && fom_count >= bicolor_count) { count -= fom_count; OUT_COPY_COUNT1(count, s, temp_s); OUT_FOM_COUNT1(fom_count, s, fom_mask, fom_mask_len); RESET_COUNTS; } fom_count = 0; fom_mask_len = 0; } last_line = line; line = line - width; start_line--; lines_sent++; } if (fill_count > 3 && fill_count >= color_count && fill_count >= bicolor_count && fill_count >= mix_count && fill_count >= fom_count) { count -= fill_count; OUT_COPY_COUNT1(count, s, temp_s); OUT_FILL_COUNT1(fill_count, s); } else if (mix_count > 3 && mix_count >= color_count && mix_count >= bicolor_count && mix_count >= fill_count && mix_count >= fom_count) { count -= mix_count; OUT_COPY_COUNT1(count, s, temp_s); OUT_MIX_COUNT1(mix_count, s); } else if (color_count > 3 && color_count >= mix_count && color_count >= bicolor_count && color_count >= fill_count && color_count >= fom_count) { count -= color_count; OUT_COPY_COUNT1(count, s, temp_s); OUT_COLOR_COUNT1(color_count, s, last_pixel); } else if (bicolor_count > 3 && bicolor_count >= mix_count && bicolor_count >= color_count && bicolor_count >= fill_count && bicolor_count >= fom_count) { if ((bicolor_count % 2) == 0) { count -= bicolor_count; OUT_COPY_COUNT1(count, s, temp_s); OUT_BICOLOR_COUNT1(bicolor_count, s, bicolor1, bicolor2); } else { bicolor_count--; count -= bicolor_count; OUT_COPY_COUNT1(count, s, temp_s); OUT_BICOLOR_COUNT1(bicolor_count, s, bicolor2, bicolor1); } count -= bicolor_count; OUT_COPY_COUNT1(count, s, temp_s); OUT_BICOLOR_COUNT1(bicolor_count, s, bicolor1, bicolor2); } else if (fom_count > 3 && fom_count >= mix_count && fom_count >= color_count && fom_count >= fill_count && fom_count >= bicolor_count) { count -= fom_count; OUT_COPY_COUNT1(count, s, temp_s); OUT_FOM_COUNT1(fom_count, s, fom_mask, fom_mask_len); } else { OUT_COPY_COUNT1(count, s, temp_s); } } else if ((bpp == 15) || (bpp == 16)) { mix = (bpp == 15) ? 0xba1f : 0xffff; out_count = end * 2; line = in_data + width * start_line * 2; while (start_line >= 0 && out_count < 32768) { i = (s->p - s->data) + count * 2; if (i - (color_count * 2) >= byte_limit && i - (bicolor_count * 2) >= byte_limit && i - (fill_count * 2) >= byte_limit && i - (mix_count * 2) >= byte_limit && i - (fom_count * 2) >= byte_limit) { break; } out_count += end * 2; for (i = 0; i < end; i++) { /* read next pixel */ IN_PIXEL16(line, i, 0, width, last_pixel, pixel); IN_PIXEL16(last_line, i, 0, width, last_ypixel, ypixel); if (!TEST_FILL) { if (fill_count > 3 && fill_count >= color_count && fill_count >= bicolor_count && fill_count >= mix_count && fill_count >= fom_count) { count -= fill_count; OUT_COPY_COUNT2(count, s, temp_s); OUT_FILL_COUNT2(fill_count, s); RESET_COUNTS; } fill_count = 0; } if (!TEST_MIX) { if (mix_count > 3 && mix_count >= fill_count && mix_count >= bicolor_count && mix_count >= color_count && mix_count >= fom_count) { count -= mix_count; OUT_COPY_COUNT2(count, s, temp_s); OUT_MIX_COUNT2(mix_count, s); RESET_COUNTS; } mix_count = 0; } if (!TEST_COLOR) { if (color_count > 3 && color_count >= fill_count && color_count >= bicolor_count && color_count >= mix_count && color_count >= fom_count) { count -= color_count; OUT_COPY_COUNT2(count, s, temp_s); OUT_COLOR_COUNT2(color_count, s, last_pixel); RESET_COUNTS; } color_count = 0; } if (!TEST_BICOLOR) { if (bicolor_count > 3 && bicolor_count >= fill_count && bicolor_count >= color_count && bicolor_count >= mix_count && bicolor_count >= fom_count) { if ((bicolor_count % 2) == 0) { count -= bicolor_count; OUT_COPY_COUNT2(count, s, temp_s); OUT_BICOLOR_COUNT2(bicolor_count, s, bicolor1, bicolor2); } else { bicolor_count--; count -= bicolor_count; OUT_COPY_COUNT2(count, s, temp_s); OUT_BICOLOR_COUNT2(bicolor_count, s, bicolor2, bicolor1); } RESET_COUNTS; } bicolor_count = 0; bicolor1 = last_pixel; bicolor2 = pixel; bicolor_spin = 0; } if (!TEST_FOM) { if (fom_count > 3 && fom_count >= fill_count && fom_count >= color_count && fom_count >= mix_count && fom_count >= bicolor_count) { count -= fom_count; OUT_COPY_COUNT2(count, s, temp_s); OUT_FOM_COUNT2(fom_count, s, fom_mask, fom_mask_len); RESET_COUNTS; } fom_count = 0; fom_mask_len = 0; } if (TEST_FILL) { fill_count++; } if (TEST_MIX) { mix_count++; } if (TEST_COLOR) { color_count++; } if (TEST_BICOLOR) { bicolor_spin = !bicolor_spin; bicolor_count++; } if (TEST_FOM) { if ((fom_count % 8) == 0) { fom_mask[fom_mask_len] = 0; fom_mask_len++; } if (pixel == (ypixel ^ mix)) { fom_mask[fom_mask_len - 1] |= (1 << (fom_count % 8)); } fom_count++; } out_uint16_le(temp_s, pixel); count++; last_pixel = pixel; last_ypixel = ypixel; } /* can't take fix, mix, or fom past first line */ if (last_line == 0) { if (fill_count > 3 && fill_count >= color_count && fill_count >= bicolor_count && fill_count >= mix_count && fill_count >= fom_count) { count -= fill_count; OUT_COPY_COUNT2(count, s, temp_s); OUT_FILL_COUNT2(fill_count, s); RESET_COUNTS; } fill_count = 0; if (mix_count > 3 && mix_count >= fill_count && mix_count >= bicolor_count && mix_count >= color_count && mix_count >= fom_count) { count -= mix_count; OUT_COPY_COUNT2(count, s, temp_s); OUT_MIX_COUNT2(mix_count, s); RESET_COUNTS; } mix_count = 0; if (fom_count > 3 && fom_count >= fill_count && fom_count >= color_count && fom_count >= mix_count && fom_count >= bicolor_count) { count -= fom_count; OUT_COPY_COUNT2(count, s, temp_s); OUT_FOM_COUNT2(fom_count, s, fom_mask, fom_mask_len); RESET_COUNTS; } fom_count = 0; fom_mask_len = 0; } last_line = line; line = line - width * 2; start_line--; lines_sent++; } if (fill_count > 3 && fill_count >= color_count && fill_count >= bicolor_count && fill_count >= mix_count && fill_count >= fom_count) { count -= fill_count; OUT_COPY_COUNT2(count, s, temp_s); OUT_FILL_COUNT2(fill_count, s); } else if (mix_count > 3 && mix_count >= color_count && mix_count >= bicolor_count && mix_count >= fill_count && mix_count >= fom_count) { count -= mix_count; OUT_COPY_COUNT2(count, s, temp_s); OUT_MIX_COUNT2(mix_count, s); } else if (color_count > 3 && color_count >= mix_count && color_count >= bicolor_count && color_count >= fill_count && color_count >= fom_count) { count -= color_count; OUT_COPY_COUNT2(count, s, temp_s); OUT_COLOR_COUNT2(color_count, s, last_pixel); } else if (bicolor_count > 3 && bicolor_count >= mix_count && bicolor_count >= color_count && bicolor_count >= fill_count && bicolor_count >= fom_count) { if ((bicolor_count % 2) == 0) { count -= bicolor_count; OUT_COPY_COUNT2(count, s, temp_s); OUT_BICOLOR_COUNT2(bicolor_count, s, bicolor1, bicolor2); } else { bicolor_count--; count -= bicolor_count; OUT_COPY_COUNT2(count, s, temp_s); OUT_BICOLOR_COUNT2(bicolor_count, s, bicolor2, bicolor1); } count -= bicolor_count; OUT_COPY_COUNT2(count, s, temp_s); OUT_BICOLOR_COUNT2(bicolor_count, s, bicolor1, bicolor2); } else if (fom_count > 3 && fom_count >= mix_count && fom_count >= color_count && fom_count >= fill_count && fom_count >= bicolor_count) { count -= fom_count; OUT_COPY_COUNT2(count, s, temp_s); OUT_FOM_COUNT2(fom_count, s, fom_mask, fom_mask_len); } else { OUT_COPY_COUNT2(count, s, temp_s); } } else if (bpp == 24) { mix = 0xffffff; out_count = end * 3; line = in_data + width * start_line * 4; while (start_line >= 0 && out_count < 32768) { i = (s->p - s->data) + count * 3; if (i - (color_count * 3) >= byte_limit && i - (bicolor_count * 3) >= byte_limit && i - (fill_count * 3) >= byte_limit && i - (mix_count * 3) >= byte_limit && i - (fom_count * 3) >= byte_limit) { break; } out_count += end * 3; for (i = 0; i < end; i++) { /* read next pixel */ IN_PIXEL32(line, i, 0, width, last_pixel, pixel); IN_PIXEL32(last_line, i, 0, width, last_ypixel, ypixel); if (!TEST_FILL) { if (fill_count > 3 && fill_count >= color_count && fill_count >= bicolor_count && fill_count >= mix_count && fill_count >= fom_count) { count -= fill_count; OUT_COPY_COUNT3(count, s, temp_s); OUT_FILL_COUNT3(fill_count, s); RESET_COUNTS; } fill_count = 0; } if (!TEST_MIX) { if (mix_count > 3 && mix_count >= fill_count && mix_count >= bicolor_count && mix_count >= color_count && mix_count >= fom_count) { count -= mix_count; OUT_COPY_COUNT3(count, s, temp_s); OUT_MIX_COUNT3(mix_count, s); RESET_COUNTS; } mix_count = 0; } if (!TEST_COLOR) { if (color_count > 3 && color_count >= fill_count && color_count >= bicolor_count && color_count >= mix_count && color_count >= fom_count) { count -= color_count; OUT_COPY_COUNT3(count, s, temp_s); OUT_COLOR_COUNT3(color_count, s, last_pixel); RESET_COUNTS; } color_count = 0; } if (!TEST_BICOLOR) { if (bicolor_count > 3 && bicolor_count >= fill_count && bicolor_count >= color_count && bicolor_count >= mix_count && bicolor_count >= fom_count) { if ((bicolor_count % 2) == 0) { count -= bicolor_count; OUT_COPY_COUNT3(count, s, temp_s); OUT_BICOLOR_COUNT3(bicolor_count, s, bicolor1, bicolor2); } else { bicolor_count--; count -= bicolor_count; OUT_COPY_COUNT3(count, s, temp_s); OUT_BICOLOR_COUNT3(bicolor_count, s, bicolor2, bicolor1); } RESET_COUNTS; } bicolor_count = 0; bicolor1 = last_pixel; bicolor2 = pixel; bicolor_spin = 0; } if (!TEST_FOM) { if (fom_count > 3 && fom_count >= fill_count && fom_count >= color_count && fom_count >= mix_count && fom_count >= bicolor_count) { count -= fom_count; OUT_COPY_COUNT3(count, s, temp_s); OUT_FOM_COUNT3(fom_count, s, fom_mask, fom_mask_len); RESET_COUNTS; } fom_count = 0; fom_mask_len = 0; } if (TEST_FILL) { fill_count++; } if (TEST_MIX) { mix_count++; } if (TEST_COLOR) { color_count++; } if (TEST_BICOLOR) { bicolor_spin = !bicolor_spin; bicolor_count++; } if (TEST_FOM) { if ((fom_count % 8) == 0) { fom_mask[fom_mask_len] = 0; fom_mask_len++; } if (pixel == (ypixel ^ mix)) { fom_mask[fom_mask_len - 1] |= (1 << (fom_count % 8)); } fom_count++; } out_uint8(temp_s, pixel & 0xff); out_uint8(temp_s, (pixel >> 8) & 0xff); out_uint8(temp_s, (pixel >> 16) & 0xff); count++; last_pixel = pixel; last_ypixel = ypixel; } /* can't take fix, mix, or fom past first line */ if (last_line == 0) { if (fill_count > 3 && fill_count >= color_count && fill_count >= bicolor_count && fill_count >= mix_count && fill_count >= fom_count) { count -= fill_count; OUT_COPY_COUNT3(count, s, temp_s); OUT_FILL_COUNT3(fill_count, s); RESET_COUNTS; } fill_count = 0; if (mix_count > 3 && mix_count >= fill_count && mix_count >= bicolor_count && mix_count >= color_count && mix_count >= fom_count) { count -= mix_count; OUT_COPY_COUNT3(count, s, temp_s); OUT_MIX_COUNT3(mix_count, s); RESET_COUNTS; } mix_count = 0; if (fom_count > 3 && fom_count >= fill_count && fom_count >= color_count && fom_count >= mix_count && fom_count >= bicolor_count) { count -= fom_count; OUT_COPY_COUNT3(count, s, temp_s); OUT_FOM_COUNT3(fom_count, s, fom_mask, fom_mask_len); RESET_COUNTS; } fom_count = 0; fom_mask_len = 0; } last_line = line; line = line - width * 4; start_line--; lines_sent++; } if (fill_count > 3 && fill_count >= color_count && fill_count >= bicolor_count && fill_count >= mix_count && fill_count >= fom_count) { count -= fill_count; OUT_COPY_COUNT3(count, s, temp_s); OUT_FILL_COUNT3(fill_count, s); } else if (mix_count > 3 && mix_count >= color_count && mix_count >= bicolor_count && mix_count >= fill_count && mix_count >= fom_count) { count -= mix_count; OUT_COPY_COUNT3(count, s, temp_s); OUT_MIX_COUNT3(mix_count, s); } else if (color_count > 3 && color_count >= mix_count && color_count >= bicolor_count && color_count >= fill_count && color_count >= fom_count) { count -= color_count; OUT_COPY_COUNT3(count, s, temp_s); OUT_COLOR_COUNT3(color_count, s, last_pixel); } else if (bicolor_count > 3 && bicolor_count >= mix_count && bicolor_count >= color_count && bicolor_count >= fill_count && bicolor_count >= fom_count) { if ((bicolor_count % 2) == 0) { count -= bicolor_count; OUT_COPY_COUNT3(count, s, temp_s); OUT_BICOLOR_COUNT3(bicolor_count, s, bicolor1, bicolor2); } else { bicolor_count--; count -= bicolor_count; OUT_COPY_COUNT3(count, s, temp_s); OUT_BICOLOR_COUNT3(bicolor_count, s, bicolor2, bicolor1); } count -= bicolor_count; OUT_COPY_COUNT3(count, s, temp_s); OUT_BICOLOR_COUNT3(bicolor_count, s, bicolor1, bicolor2); } else if (fom_count > 3 && fom_count >= mix_count && fom_count >= color_count && fom_count >= fill_count && fom_count >= bicolor_count) { count -= fom_count; OUT_COPY_COUNT3(count, s, temp_s); OUT_FOM_COUNT3(fom_count, s, fom_mask, fom_mask_len); } else { OUT_COPY_COUNT3(count, s, temp_s); } } return lines_sent; } xrdp-0.6.0/libxrdp/xrdp_channel.c000066400000000000000000000121111203155130500167360ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2006-2010 channel layer */ #include "libxrdp.h" /* todo, move these to constants.h */ //#define CHANNEL_CHUNK_LENGTH 1600 /* todo, why is this so small? */ #define CHANNEL_CHUNK_LENGTH 8192 #define CHANNEL_FLAG_FIRST 0x01 #define CHANNEL_FLAG_LAST 0x02 #define CHANNEL_FLAG_SHOW_PROTOCOL 0x10 /*****************************************************************************/ /* returns pointer or nil on error */ static struct mcs_channel_item* APP_CC xrdp_channel_get_item(struct xrdp_channel* self, int channel_id) { struct mcs_channel_item* channel; channel = (struct mcs_channel_item*) list_get_item(self->mcs_layer->channel_list, channel_id); return channel; } /*****************************************************************************/ struct xrdp_channel* APP_CC xrdp_channel_create(struct xrdp_sec* owner, struct xrdp_mcs* mcs_layer) { struct xrdp_channel* self; self = (struct xrdp_channel*)g_malloc(sizeof(struct xrdp_channel), 1); self->sec_layer = owner; self->mcs_layer = mcs_layer; return self; } /*****************************************************************************/ /* returns error */ void APP_CC xrdp_channel_delete(struct xrdp_channel* self) { if (self == 0) { return; } g_free(self); } /*****************************************************************************/ /* returns error */ int APP_CC xrdp_channel_init(struct xrdp_channel* self, struct stream* s) { if (xrdp_sec_init(self->sec_layer, s) != 0) { return 1; } s_push_layer(s, channel_hdr, 8); return 0; } /*****************************************************************************/ /* returns error */ /* This sends data out to the secure layer. */ int APP_CC xrdp_channel_send(struct xrdp_channel* self, struct stream* s, int channel_id, int total_data_len, int flags) { struct mcs_channel_item* channel; channel = xrdp_channel_get_item(self, channel_id); if (channel == 0) { return 1; } s_pop_layer(s, channel_hdr); out_uint32_le(s, total_data_len); if (channel->flags & CHANNEL_OPTION_SHOW_PROTOCOL) { flags |= CHANNEL_FLAG_SHOW_PROTOCOL; } out_uint32_le(s, flags); if (xrdp_sec_send(self->sec_layer, s, channel->chanid) != 0) { return 1; } return 0; } /*****************************************************************************/ /* returns error */ /* this will inform the callback, whatever it is that some channel data is ready. the default for this is a call to xrdp_wm.c. */ static int APP_CC xrdp_channel_call_callback(struct xrdp_channel* self, struct stream* s, int channel_id, int total_data_len, int flags) { struct xrdp_session* session; int rv; int size; rv = 0; session = self->sec_layer->rdp_layer->session; if (session != 0) { if (session->callback != 0) { size = (int)(s->end - s->p); /* in xrdp_wm.c */ rv = session->callback(session->id, 0x5555, MAKELONG(channel_id, flags), size, (tbus)(s->p), total_data_len); } else { g_writeln("in xrdp_channel_call_callback, session->callback is nil"); } } else { g_writeln("in xrdp_channel_call_callback, session is nil"); } return rv; } /*****************************************************************************/ /* returns error */ /* This is called from the secure layer to process an incomming non global channel packet. 'chanid' passed in here is the mcs channel id so it MCS_GLOBAL_CHANNEL plus something. */ int APP_CC xrdp_channel_process(struct xrdp_channel* self, struct stream* s, int chanid) { int length; int flags; int rv; int channel_id; struct mcs_channel_item* channel; /* this assumes that the channels are in order of chanid(mcs channel id) but they should be, see xrdp_sec_process_mcs_data_channels the first channel should be MCS_GLOBAL_CHANNEL + 1, second one should be MCS_GLOBAL_CHANNEL + 2, and so on */ channel_id = (chanid - MCS_GLOBAL_CHANNEL) - 1; channel = xrdp_channel_get_item(self, channel_id); if (channel == 0) { g_writeln("xrdp_channel_process, channel not found"); return 1; } rv = 0; in_uint32_le(s, length); in_uint32_le(s, flags); rv = xrdp_channel_call_callback(self, s, channel_id, length, flags); return rv; } xrdp-0.6.0/libxrdp/xrdp_iso.c000066400000000000000000000105651203155130500161330ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2004-2010 iso layer */ #include "libxrdp.h" /*****************************************************************************/ struct xrdp_iso* APP_CC xrdp_iso_create(struct xrdp_mcs* owner, struct trans* trans) { struct xrdp_iso* self; DEBUG((" in xrdp_iso_create")); self = (struct xrdp_iso*)g_malloc(sizeof(struct xrdp_iso), 1); self->mcs_layer = owner; self->tcp_layer = xrdp_tcp_create(self, trans); DEBUG((" out xrdp_iso_create")); return self; } /*****************************************************************************/ void APP_CC xrdp_iso_delete(struct xrdp_iso* self) { if (self == 0) { return; } xrdp_tcp_delete(self->tcp_layer); g_free(self); } /*****************************************************************************/ /* returns error */ static int APP_CC xrdp_iso_recv_msg(struct xrdp_iso* self, struct stream* s, int* code) { int ver; int len; *code = 0; if (xrdp_tcp_recv(self->tcp_layer, s, 4) != 0) { return 1; } in_uint8(s, ver); if (ver != 3) { return 1; } in_uint8s(s, 1); in_uint16_be(s, len); if (xrdp_tcp_recv(self->tcp_layer, s, len - 4) != 0) { return 1; } in_uint8s(s, 1); in_uint8(s, *code); if (*code == ISO_PDU_DT) { in_uint8s(s, 1); } else { in_uint8s(s, 5); } return 0; } /*****************************************************************************/ /* returns error */ int APP_CC xrdp_iso_recv(struct xrdp_iso* self, struct stream* s) { int code; DEBUG((" in xrdp_iso_recv")); if (xrdp_iso_recv_msg(self, s, &code) != 0) { DEBUG((" out xrdp_iso_recv xrdp_iso_recv_msg return non zero")); return 1; } if (code != ISO_PDU_DT) { DEBUG((" out xrdp_iso_recv code != ISO_PDU_DT")); return 1; } DEBUG((" out xrdp_iso_recv")); return 0; } /*****************************************************************************/ static int APP_CC xrdp_iso_send_msg(struct xrdp_iso* self, struct stream* s, int code) { if (xrdp_tcp_init(self->tcp_layer, s) != 0) { return 1; } out_uint8(s, 3); out_uint8(s, 0); out_uint16_be(s, 11); /* length */ out_uint8(s, 6); out_uint8(s, code); out_uint16_le(s, 0); out_uint16_le(s, 0); out_uint8(s, 0); s_mark_end(s); if (xrdp_tcp_send(self->tcp_layer, s) != 0) { return 1; } return 0; } /*****************************************************************************/ /* returns error */ int APP_CC xrdp_iso_incoming(struct xrdp_iso* self) { int code; struct stream* s; make_stream(s); init_stream(s, 8192); DEBUG((" in xrdp_iso_incoming")); if (xrdp_iso_recv_msg(self, s, &code) != 0) { free_stream(s); return 1; } if (code != ISO_PDU_CR) { free_stream(s); return 1; } if (xrdp_iso_send_msg(self, s, ISO_PDU_CC) != 0) { free_stream(s); return 1; } DEBUG((" out xrdp_iso_incoming")); free_stream(s); return 0; } /*****************************************************************************/ /* returns error */ int APP_CC xrdp_iso_init(struct xrdp_iso* self, struct stream* s) { xrdp_tcp_init(self->tcp_layer, s); s_push_layer(s, iso_hdr, 7); return 0; } /*****************************************************************************/ /* returns error */ int APP_CC xrdp_iso_send(struct xrdp_iso* self, struct stream* s) { int len; DEBUG((" in xrdp_iso_send")); s_pop_layer(s, iso_hdr); len = s->end - s->p; out_uint8(s, 3); out_uint8(s, 0); out_uint16_be(s, len); out_uint8(s, 2); out_uint8(s, ISO_PDU_DT); out_uint8(s, 0x80); if (xrdp_tcp_send(self->tcp_layer, s) != 0) { return 1; } DEBUG((" out xrdp_iso_send")); return 0; } xrdp-0.6.0/libxrdp/xrdp_mcs.c000066400000000000000000000405131203155130500161170ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2004-2010 mcs layer */ #include "libxrdp.h" /*****************************************************************************/ struct xrdp_mcs* APP_CC xrdp_mcs_create(struct xrdp_sec* owner, struct trans* trans, struct stream* client_mcs_data, struct stream* server_mcs_data) { struct xrdp_mcs* self; DEBUG((" in xrdp_mcs_create")); self = (struct xrdp_mcs*)g_malloc(sizeof(struct xrdp_mcs), 1); self->sec_layer = owner; self->userid = 1; self->chanid = 1001; self->client_mcs_data = client_mcs_data; self->server_mcs_data = server_mcs_data; self->iso_layer = xrdp_iso_create(self, trans); self->channel_list = list_create(); DEBUG((" out xrdp_mcs_create")); return self; } /*****************************************************************************/ void APP_CC xrdp_mcs_delete(struct xrdp_mcs* self) { struct mcs_channel_item* channel_item; int index; int count; if (self == 0) { return; } /* here we have to free the channel items and anything in them */ count = self->channel_list->count; for (index = count - 1; index >= 0; index--) { channel_item = (struct mcs_channel_item*) list_get_item(self->channel_list, index); g_free(channel_item); } list_delete(self->channel_list); xrdp_iso_delete(self->iso_layer); g_free(self); } /*****************************************************************************/ /* returns error */ static int APP_CC xrdp_mcs_send_cjcf(struct xrdp_mcs* self, int userid, int chanid) { struct stream* s; DEBUG((" in xrdp_mcs_send_cjcf")); make_stream(s); init_stream(s, 8192); if (xrdp_iso_init(self->iso_layer, s) != 0) { free_stream(s); DEBUG((" out xrdp_mcs_send_cjcf error")); return 1; } out_uint8(s, (MCS_CJCF << 2) | 2); out_uint8(s, 0); out_uint16_be(s, userid); out_uint16_be(s, chanid); out_uint16_be(s, chanid); s_mark_end(s); if (xrdp_iso_send(self->iso_layer, s) != 0) { free_stream(s); DEBUG((" out xrdp_mcs_send_cjcf error")); return 1; } free_stream(s); DEBUG((" out xrdp_mcs_send_cjcf")); return 0; } /*****************************************************************************/ /* returns error */ int APP_CC xrdp_mcs_recv(struct xrdp_mcs* self, struct stream* s, int* chan) { int appid; int opcode; int len; int userid; int chanid; DEBUG((" in xrdp_mcs_recv")); while (1) { if (xrdp_iso_recv(self->iso_layer, s) != 0) { DEBUG((" out xrdp_mcs_recv xrdp_iso_recv returned non zero")); return 1; } in_uint8(s, opcode); appid = opcode >> 2; if (appid == MCS_DPUM) { DEBUG((" out xrdp_mcs_recv appid != MCS_DPUM")); return 1; } /* this is channels getting added from the client */ if (appid == MCS_CJRQ) { in_uint16_be(s, userid); in_uint16_be(s, chanid); DEBUG((" adding channel %4.4x", chanid)); xrdp_mcs_send_cjcf(self, userid, chanid); continue; } break; } if (appid != MCS_SDRQ) { DEBUG((" out xrdp_mcs_recv err got 0x%x need MCS_SDRQ", appid)); return 1; } in_uint8s(s, 2); in_uint16_be(s, *chan); in_uint8s(s, 1); in_uint8(s, len); if (len & 0x80) { in_uint8s(s, 1); } DEBUG((" out xrdp_mcs_recv")); return 0; } /*****************************************************************************/ /* returns error */ static int APP_CC xrdp_mcs_ber_parse_header(struct xrdp_mcs* self, struct stream* s, int tag_val, int* len) { int tag; int l; int i; if (tag_val > 0xff) { in_uint16_be(s, tag); } else { in_uint8(s, tag); } if (tag != tag_val) { return 1; } in_uint8(s, l); if (l & 0x80) { l = l & ~0x80; *len = 0; while (l > 0) { in_uint8(s, i); *len = (*len << 8) | i; l--; } } else { *len = l; } if (s_check(s)) { return 0; } else { return 1; } } /*****************************************************************************/ /* returns error */ static int APP_CC xrdp_mcs_parse_domain_params(struct xrdp_mcs* self, struct stream* s) { int len; if (xrdp_mcs_ber_parse_header(self, s, MCS_TAG_DOMAIN_PARAMS, &len) != 0) { return 1; } in_uint8s(s, len); if (s_check(s)) { return 0; } else { return 1; } } /*****************************************************************************/ /* returns error */ static int APP_CC xrdp_mcs_recv_connect_initial(struct xrdp_mcs* self) { int len; struct stream* s; make_stream(s); init_stream(s, 8192); if (xrdp_iso_recv(self->iso_layer, s) != 0) { free_stream(s); return 1; } if (xrdp_mcs_ber_parse_header(self, s, MCS_CONNECT_INITIAL, &len) != 0) { free_stream(s); return 1; } if (xrdp_mcs_ber_parse_header(self, s, BER_TAG_OCTET_STRING, &len) != 0) { free_stream(s); return 1; } in_uint8s(s, len); if (xrdp_mcs_ber_parse_header(self, s, BER_TAG_OCTET_STRING, &len) != 0) { free_stream(s); return 1; } in_uint8s(s, len); if (xrdp_mcs_ber_parse_header(self, s, BER_TAG_BOOLEAN, &len) != 0) { free_stream(s); return 1; } in_uint8s(s, len); if (xrdp_mcs_parse_domain_params(self, s) != 0) { free_stream(s); return 1; } if (xrdp_mcs_parse_domain_params(self, s) != 0) { free_stream(s); return 1; } if (xrdp_mcs_parse_domain_params(self, s) != 0) { free_stream(s); return 1; } if (xrdp_mcs_ber_parse_header(self, s, BER_TAG_OCTET_STRING, &len) != 0) { free_stream(s); return 1; } /* make a copy of client mcs data */ init_stream(self->client_mcs_data, len); out_uint8a(self->client_mcs_data, s->p, len); in_uint8s(s, len); s_mark_end(self->client_mcs_data); if (s_check_end(s)) { free_stream(s); return 0; } else { free_stream(s); return 1; } } /*****************************************************************************/ /* returns error */ static int APP_CC xrdp_mcs_recv_edrq(struct xrdp_mcs* self) { int opcode; struct stream* s; make_stream(s); init_stream(s, 8192); if (xrdp_iso_recv(self->iso_layer, s) != 0) { free_stream(s); return 1; } in_uint8(s, opcode); if ((opcode >> 2) != MCS_EDRQ) { free_stream(s); return 1; } in_uint8s(s, 2); in_uint8s(s, 2); if (opcode & 2) { in_uint16_be(s, self->userid); } if (!(s_check_end(s))) { free_stream(s); return 1; } free_stream(s); return 0; } /*****************************************************************************/ /* returns error */ static int APP_CC xrdp_mcs_recv_aurq(struct xrdp_mcs* self) { int opcode; struct stream* s; make_stream(s); init_stream(s, 8192); if (xrdp_iso_recv(self->iso_layer, s) != 0) { free_stream(s); return 1; } in_uint8(s, opcode); if ((opcode >> 2) != MCS_AURQ) { free_stream(s); return 1; } if (opcode & 2) { in_uint16_be(s, self->userid); } if (!(s_check_end(s))) { free_stream(s); return 1; } free_stream(s); return 0; } /*****************************************************************************/ /* returns error */ static int APP_CC xrdp_mcs_send_aucf(struct xrdp_mcs* self) { struct stream* s; DEBUG((" in xrdp_mcs_send_aucf")); make_stream(s); init_stream(s, 8192); if (xrdp_iso_init(self->iso_layer, s) != 0) { free_stream(s); DEBUG((" out xrdp_mcs_send_aucf error")); return 1; } out_uint8(s, ((MCS_AUCF << 2) | 2)); out_uint8s(s, 1); out_uint16_be(s, self->userid); s_mark_end(s); if (xrdp_iso_send(self->iso_layer, s) != 0) { free_stream(s); DEBUG((" out xrdp_mcs_send_aucf error")); return 1; } free_stream(s); DEBUG((" out xrdp_mcs_send_aucf")); return 0; } /*****************************************************************************/ /* returns error */ static int APP_CC xrdp_mcs_recv_cjrq(struct xrdp_mcs* self) { int opcode; struct stream* s; make_stream(s); init_stream(s, 8192); if (xrdp_iso_recv(self->iso_layer, s) != 0) { free_stream(s); return 1; } in_uint8(s, opcode); if ((opcode >> 2) != MCS_CJRQ) { free_stream(s); return 1; } in_uint8s(s, 4); if (opcode & 2) { in_uint8s(s, 2); } if (!(s_check_end(s))) { free_stream(s); return 1; } free_stream(s); return 0; } /*****************************************************************************/ /* returns error */ static int APP_CC xrdp_mcs_ber_out_header(struct xrdp_mcs* self, struct stream* s, int tag_val, int len) { if (tag_val > 0xff) { out_uint16_be(s, tag_val); } else { out_uint8(s, tag_val); } if (len >= 0x80) { out_uint8(s, 0x82); out_uint16_be(s, len); } else { out_uint8(s, len); } return 0; } /*****************************************************************************/ /* returns error */ static int APP_CC xrdp_mcs_ber_out_int8(struct xrdp_mcs* self, struct stream* s, int value) { xrdp_mcs_ber_out_header(self, s, BER_TAG_INTEGER, 1); out_uint8(s, value); return 0; } #if 0 /* not used */ /*****************************************************************************/ /* returns error */ static int APP_CC xrdp_mcs_ber_out_int16(struct xrdp_mcs* self, struct stream* s, int value) { xrdp_mcs_ber_out_header(self, s, BER_TAG_INTEGER, 2); out_uint8(s, (value >> 8)); out_uint8(s, value); return 0; } #endif /*****************************************************************************/ /* returns error */ static int APP_CC xrdp_mcs_ber_out_int24(struct xrdp_mcs* self, struct stream* s, int value) { xrdp_mcs_ber_out_header(self, s, BER_TAG_INTEGER, 3); out_uint8(s, (value >> 16)); out_uint8(s, (value >> 8)); out_uint8(s, value); return 0; } /*****************************************************************************/ /* returns error */ static int APP_CC xrdp_mcs_out_domain_params(struct xrdp_mcs* self, struct stream* s, int max_channels, int max_users, int max_tokens, int max_pdu_size) { xrdp_mcs_ber_out_header(self, s, MCS_TAG_DOMAIN_PARAMS, 26); xrdp_mcs_ber_out_int8(self, s, max_channels); xrdp_mcs_ber_out_int8(self, s, max_users); xrdp_mcs_ber_out_int8(self, s, max_tokens); xrdp_mcs_ber_out_int8(self, s, 1); xrdp_mcs_ber_out_int8(self, s, 0); xrdp_mcs_ber_out_int8(self, s, 1); xrdp_mcs_ber_out_int24(self, s, max_pdu_size); xrdp_mcs_ber_out_int8(self, s, 2); return 0; } /*****************************************************************************/ /* returns error */ static int APP_CC xrdp_mcs_send_connect_response(struct xrdp_mcs* self) { int data_len; struct stream* s; DEBUG((" in xrdp_mcs_send_connect_response")); make_stream(s); init_stream(s, 8192); data_len = self->server_mcs_data->end - self->server_mcs_data->data; xrdp_iso_init(self->iso_layer, s); xrdp_mcs_ber_out_header(self, s, MCS_CONNECT_RESPONSE, data_len + 38); xrdp_mcs_ber_out_header(self, s, BER_TAG_RESULT, 1); out_uint8(s, 0); xrdp_mcs_ber_out_header(self, s, BER_TAG_INTEGER, 1); out_uint8(s, 0); xrdp_mcs_out_domain_params(self, s, 22, 3, 0, 0xfff8); xrdp_mcs_ber_out_header(self, s, BER_TAG_OCTET_STRING, data_len); /* mcs data */ out_uint8a(s, self->server_mcs_data->data, data_len); s_mark_end(s); if (xrdp_iso_send(self->iso_layer, s) != 0) { free_stream(s); DEBUG((" out xrdp_mcs_send_connect_response error")); return 1; } free_stream(s); DEBUG((" out xrdp_mcs_send_connect_response")); return 0; } /*****************************************************************************/ /* returns error */ int APP_CC xrdp_mcs_incoming(struct xrdp_mcs* self) { DEBUG((" in xrdp_mcs_incoming")); if (xrdp_iso_incoming(self->iso_layer) != 0) { return 1; } if (xrdp_mcs_recv_connect_initial(self) != 0) { return 1; } /* in xrdp_sec.c */ if (xrdp_sec_process_mcs_data(self->sec_layer) != 0) { return 1; } /* in xrdp_sec.c */ if (xrdp_sec_out_mcs_data(self->sec_layer) != 0) { return 1; } if (xrdp_mcs_send_connect_response(self) != 0) { return 1; } if (xrdp_mcs_recv_edrq(self) != 0) { return 1; } if (xrdp_mcs_recv_aurq(self) != 0) { return 1; } if (xrdp_mcs_send_aucf(self) != 0) { return 1; } if (xrdp_mcs_recv_cjrq(self) != 0) { return 1; } if (xrdp_mcs_send_cjcf(self, self->userid, self->userid + MCS_USERCHANNEL_BASE) != 0) { return 1; } if (xrdp_mcs_recv_cjrq(self) != 0) { return 1; } if (xrdp_mcs_send_cjcf(self, self->userid, MCS_GLOBAL_CHANNEL) != 0) { return 1; } DEBUG((" out xrdp_mcs_incoming")); return 0; } /*****************************************************************************/ /* returns error */ int APP_CC xrdp_mcs_init(struct xrdp_mcs* self, struct stream* s) { xrdp_iso_init(self->iso_layer, s); s_push_layer(s, mcs_hdr, 8); return 0; } /*****************************************************************************/ /* returns error */ /* Inform the callback that an mcs packet has been sent. This is needed so the module can send any high priority mcs packets like audio. */ static int APP_CC xrdp_mcs_call_callback(struct xrdp_mcs* self) { int rv; struct xrdp_session* session; rv = 0; /* if there is a callback, call it here */ session = self->sec_layer->rdp_layer->session; if (session != 0) { if (session->callback != 0) { /* in xrdp_wm.c */ rv = session->callback(session->id, 0x5556, 0, 0, 0, 0); } else { g_writeln("in xrdp_mcs_send, session->callback is nil"); } } else { g_writeln("in xrdp_mcs_send, session is nil"); } return rv; } /*****************************************************************************/ /* returns error */ int APP_CC xrdp_mcs_send(struct xrdp_mcs* self, struct stream* s, int chan) { int len; char* lp; //static int max_len = 0; DEBUG((" in xrdp_mcs_send")); s_pop_layer(s, mcs_hdr); len = (s->end - s->p) - 8; if (len > 8192 * 2) { g_writeln("error in xrdp_mcs_send, size too bog, its %d", len); } //if (len > max_len) //{ // max_len = len; // g_printf("mcs max length is %d\r\n", max_len); //} //g_printf("mcs length %d max length is %d\r\n", len, max_len); //g_printf("mcs length %d\r\n", len); out_uint8(s, MCS_SDIN << 2); out_uint16_be(s, self->userid); out_uint16_be(s, chan); out_uint8(s, 0x70); if (len >= 128) { len = len | 0x8000; out_uint16_be(s, len); } else { out_uint8(s, len); /* move everything up one byte */ lp = s->p; while (lp < s->end) { lp[0] = lp[1]; lp++; } s->end--; } if (xrdp_iso_send(self->iso_layer, s) != 0) { DEBUG((" out xrdp_mcs_send error")); return 1; } /* todo, do we need to call this for every mcs packet, maybe every 5 or so */ if (chan == MCS_GLOBAL_CHANNEL) { xrdp_mcs_call_callback(self); } DEBUG((" out xrdp_mcs_send")); return 0; } /*****************************************************************************/ /* returns error */ int APP_CC xrdp_mcs_disconnect(struct xrdp_mcs* self) { struct stream* s; DEBUG((" in xrdp_mcs_disconnect")); make_stream(s); init_stream(s, 8192); if (xrdp_iso_init(self->iso_layer, s) != 0) { free_stream(s); DEBUG((" out xrdp_mcs_disconnect error")); return 1; } out_uint8(s, (MCS_DPUM << 2) | 1); out_uint8(s, 0x80); s_mark_end(s); if (xrdp_iso_send(self->iso_layer, s) != 0) { free_stream(s); DEBUG((" out xrdp_mcs_disconnect error")); return 1; } free_stream(s); DEBUG((" out xrdp_mcs_disconnect")); return 0; } xrdp-0.6.0/libxrdp/xrdp_orders.c000066400000000000000000001456511203155130500166440ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2004-2010 orders */ #include "libxrdp.h" /*****************************************************************************/ struct xrdp_orders* APP_CC xrdp_orders_create(struct xrdp_session* session, struct xrdp_rdp* rdp_layer) { struct xrdp_orders* self; self = (struct xrdp_orders*)g_malloc(sizeof(struct xrdp_orders), 1); self->session = session; self->rdp_layer = rdp_layer; make_stream(self->out_s); init_stream(self->out_s, 16384); self->orders_state.clip_right = 1; /* silly rdp right clip */ self->orders_state.clip_bottom = 1; /* silly rdp bottom clip */ return self; } /*****************************************************************************/ void APP_CC xrdp_orders_delete(struct xrdp_orders* self) { if (self == 0) { return; } free_stream(self->out_s); g_free(self->orders_state.text_data); g_free(self); } /*****************************************************************************/ /* set all values to zero */ /* returns error */ int APP_CC xrdp_orders_reset(struct xrdp_orders* self) { if (xrdp_orders_force_send(self) != 0) { return 1; } g_free(self->orders_state.text_data); g_memset(&(self->orders_state), 0, sizeof(self->orders_state)); self->order_count_ptr = 0; self->order_count = 0; self->order_level = 0; self->orders_state.clip_right = 1; /* silly rdp right clip */ self->orders_state.clip_bottom = 1; /* silly rdp bottom clip */ return 0; } /*****************************************************************************/ /* returns error */ int APP_CC xrdp_orders_init(struct xrdp_orders* self) { self->order_level++; if (self->order_level == 1) { self->order_count = 0; /* is this big enough */ if (xrdp_rdp_init_data(self->rdp_layer, self->out_s) != 0) { return 1; } out_uint16_le(self->out_s, RDP_UPDATE_ORDERS); out_uint8s(self->out_s, 2); /* pad */ self->order_count_ptr = self->out_s->p; out_uint8s(self->out_s, 2); /* number of orders, set later */ out_uint8s(self->out_s, 2); /* pad */ } return 0; } /*****************************************************************************/ /* returns error */ int APP_CC xrdp_orders_send(struct xrdp_orders* self) { int rv; rv = 0; if (self->order_level > 0) { self->order_level--; if ((self->order_level == 0) && (self->order_count > 0)) { s_mark_end(self->out_s); DEBUG(("xrdp_orders_send sending %d orders", self->order_count)); self->order_count_ptr[0] = self->order_count; self->order_count_ptr[1] = self->order_count >> 8; self->order_count = 0; if (xrdp_rdp_send_data(self->rdp_layer, self->out_s, RDP_DATA_PDU_UPDATE) != 0) { rv = 1; } } } return rv; } /*****************************************************************************/ /* returns error */ int APP_CC xrdp_orders_force_send(struct xrdp_orders* self) { if (self == 0) { return 1; } if ((self->order_level > 0) && (self->order_count > 0)) { s_mark_end(self->out_s); DEBUG(("xrdp_orders_force_send sending %d orders", self->order_count)); self->order_count_ptr[0] = self->order_count; self->order_count_ptr[1] = self->order_count >> 8; if (xrdp_rdp_send_data(self->rdp_layer, self->out_s, RDP_DATA_PDU_UPDATE) != 0) { return 1; } } self->order_count = 0; self->order_level = 0; return 0; } /*****************************************************************************/ /* check if the current order will fit in packet size of 16384, if not */ /* send what we got and init a new one */ /* returns error */ static int APP_CC xrdp_orders_check(struct xrdp_orders* self, int max_size) { int size; int max_packet_size; if (self->rdp_layer->client_info.bpp == 8) { max_packet_size = 8000; } else { max_packet_size = 16000; } if (self->order_level < 1) { if (max_size > max_packet_size) { return 1; } else { return 0; } } size = (int)(self->out_s->p - self->order_count_ptr); if ((size < 0) || (size > max_packet_size)) { return 1; } if ((size + max_size + 100) > max_packet_size) { xrdp_orders_force_send(self); xrdp_orders_init(self); } return 0; } /*****************************************************************************/ /* check if rect is the same as the last one sent */ /* returns boolean */ static int APP_CC xrdp_orders_last_bounds(struct xrdp_orders* self, struct xrdp_rect* rect) { if (rect == 0) { return 0; } if ((rect->left == self->orders_state.clip_left) && (rect->top == self->orders_state.clip_top) && (rect->right == self->orders_state.clip_right) && (rect->bottom == self->orders_state.clip_bottom)) { return 1; } return 0; } /*****************************************************************************/ /* check if all coords are withing 256 bytes */ /* returns boolean */ static int APP_CC xrdp_orders_send_delta(struct xrdp_orders* self, int* vals, int count) { int i; for (i = 0; i < count; i += 2) { if (g_abs(vals[i] - vals[i + 1]) >= 128) { return 0; } } return 1; } /*****************************************************************************/ /* returns error */ static int APP_CC xrdp_orders_out_bounds(struct xrdp_orders* self, struct xrdp_rect* rect) { char* bounds_flags_ptr; int bounds_flags; bounds_flags = 0; bounds_flags_ptr = self->out_s->p; out_uint8s(self->out_s, 1); /* left */ if (rect->left == self->orders_state.clip_left) { } else if (g_abs(rect->left - self->orders_state.clip_left) < 128) { bounds_flags |= 0x10; } else { bounds_flags |= 0x01; } /* top */ if (rect->top == self->orders_state.clip_top) { } else if (g_abs(rect->top - self->orders_state.clip_top) < 128) { bounds_flags |= 0x20; } else { bounds_flags |= 0x02; } /* right */ if (rect->right == self->orders_state.clip_right) { } else if (g_abs(rect->right - self->orders_state.clip_right) < 128) { bounds_flags |= 0x40; } else { bounds_flags |= 0x04; } /* bottom */ if (rect->bottom == self->orders_state.clip_bottom) { } else if (g_abs(rect->bottom - self->orders_state.clip_bottom) < 128) { bounds_flags |= 0x80; } else { bounds_flags |= 0x08; } /* left */ if (bounds_flags & 0x01) { out_uint16_le(self->out_s, rect->left); } else if (bounds_flags & 0x10) { out_uint8(self->out_s, rect->left - self->orders_state.clip_left); } self->orders_state.clip_left = rect->left; /* top */ if (bounds_flags & 0x02) { out_uint16_le(self->out_s, rect->top); } else if (bounds_flags & 0x20) { out_uint8(self->out_s, rect->top - self->orders_state.clip_top); } self->orders_state.clip_top = rect->top; /* right */ if (bounds_flags & 0x04) { out_uint16_le(self->out_s, rect->right - 1); /* silly rdp right clip */ } else if (bounds_flags & 0x40) { out_uint8(self->out_s, rect->right - self->orders_state.clip_right); } self->orders_state.clip_right = rect->right; /* bottom */ if (bounds_flags & 0x08) { out_uint16_le(self->out_s, rect->bottom - 1); /* silly rdp bottom clip */ } else if (bounds_flags & 0x80) { out_uint8(self->out_s, rect->bottom - self->orders_state.clip_bottom); } self->orders_state.clip_bottom = rect->bottom; /* set flags */ *bounds_flags_ptr = bounds_flags; return 0; } /*****************************************************************************/ /* returns error */ static int APP_CC xrdp_order_pack_small_or_tiny(struct xrdp_orders* self, char* order_flags_ptr, int orders_flags, char* present_ptr, int present, int present_size) { int move_up_count = 0; int index = 0; int size = 0; int keep_looking = 1; move_up_count = 0; keep_looking = 1; for (index = present_size - 1; index >= 0; index--) { if (keep_looking) { if (((present >> (index * 8)) & 0xff) == 0) { move_up_count++; } else { keep_looking = 0; } } present_ptr[index] = present >> (index * 8); } if (move_up_count > 0) { /* move_up_count should be 0, 1, 2, or 3 shifting it 6 will make it RDP_ORDER_TINY(0x80) or RDP_ORDER_SMALL(0x40) or both */ orders_flags |= move_up_count << 6; size = (int)(self->out_s->p - present_ptr); size -= present_size; for (index = 0; index < size; index++) { present_ptr[index + (present_size - move_up_count)] = present_ptr[index + present_size]; } self->out_s->p -= move_up_count; } order_flags_ptr[0] = orders_flags; return 0; } /*****************************************************************************/ /* returns error */ /* send a solid rect to client */ /* max size 23 */ int APP_CC xrdp_orders_rect(struct xrdp_orders* self, int x, int y, int cx, int cy, int color, struct xrdp_rect* rect) { int order_flags; int vals[8]; int present; char* present_ptr; char* order_flags_ptr; xrdp_orders_check(self, 23); self->order_count++; order_flags = RDP_ORDER_STANDARD; if (self->orders_state.last_order != RDP_ORDER_RECT) { order_flags |= RDP_ORDER_CHANGE; } self->orders_state.last_order = RDP_ORDER_RECT; if (rect != 0) { /* if clip is present, still check if its needed */ if (x < rect->left || y < rect->top || x + cx > rect->right || y + cy > rect->bottom) { order_flags |= RDP_ORDER_BOUNDS; if (xrdp_orders_last_bounds(self, rect)) { order_flags |= RDP_ORDER_LASTBOUNDS; } } } vals[0] = x; vals[1] = self->orders_state.rect_x; vals[2] = y; vals[3] = self->orders_state.rect_y; vals[4] = cx; vals[5] = self->orders_state.rect_cx; vals[6] = cy; vals[7] = self->orders_state.rect_cy; if (xrdp_orders_send_delta(self, vals, 8)) { order_flags |= RDP_ORDER_DELTA; } /* order_flags, set later, 1 byte */ order_flags_ptr = self->out_s->p; out_uint8s(self->out_s, 1); if (order_flags & RDP_ORDER_CHANGE) { out_uint8(self->out_s, self->orders_state.last_order); } present = 0; /* present, set later, 1 byte */ present_ptr = self->out_s->p; out_uint8s(self->out_s, 1); if ((order_flags & RDP_ORDER_BOUNDS) && !(order_flags & RDP_ORDER_LASTBOUNDS)) { xrdp_orders_out_bounds(self, rect); } if (x != self->orders_state.rect_x) { present |= 0x01; if (order_flags & RDP_ORDER_DELTA) { out_uint8(self->out_s, x - self->orders_state.rect_x); } else { out_uint16_le(self->out_s, x); } self->orders_state.rect_x = x; } if (y != self->orders_state.rect_y) { present |= 0x02; if (order_flags & RDP_ORDER_DELTA) { out_uint8(self->out_s, y - self->orders_state.rect_y); } else { out_uint16_le(self->out_s, y); } self->orders_state.rect_y = y; } if (cx != self->orders_state.rect_cx) { present |= 0x04; if (order_flags & RDP_ORDER_DELTA) { out_uint8(self->out_s, cx - self->orders_state.rect_cx); } else { out_uint16_le(self->out_s, cx); } self->orders_state.rect_cx = cx; } if (cy != self->orders_state.rect_cy) { present |= 0x08; if (order_flags & RDP_ORDER_DELTA) { out_uint8(self->out_s, cy - self->orders_state.rect_cy); } else { out_uint16_le(self->out_s, cy); } self->orders_state.rect_cy = cy; } if ((color & 0xff) != (self->orders_state.rect_color & 0xff)) { present |= 0x10; self->orders_state.rect_color = (self->orders_state.rect_color & 0xffff00) | (color & 0xff); out_uint8(self->out_s, color); } if ((color & 0xff00) != (self->orders_state.rect_color & 0xff00)) { present |= 0x20; self->orders_state.rect_color = (self->orders_state.rect_color & 0xff00ff) | (color & 0xff00); out_uint8(self->out_s, color >> 8); } if ((color & 0xff0000) != (self->orders_state.rect_color & 0xff0000)) { present |= 0x40; self->orders_state.rect_color = (self->orders_state.rect_color & 0x00ffff) | (color & 0xff0000); out_uint8(self->out_s, color >> 16); } xrdp_order_pack_small_or_tiny(self, order_flags_ptr, order_flags, present_ptr, present, 1); return 0; } /*****************************************************************************/ /* returns error */ /* send a screen blt order */ /* max size 25 */ int APP_CC xrdp_orders_screen_blt(struct xrdp_orders* self, int x, int y, int cx, int cy, int srcx, int srcy, int rop, struct xrdp_rect* rect) { int order_flags = 0; int vals[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; int present = 0; char* present_ptr = (char *)NULL; char* order_flags_ptr = (char *)NULL; xrdp_orders_check(self, 25); self->order_count++; order_flags = RDP_ORDER_STANDARD; if (self->orders_state.last_order != RDP_ORDER_SCREENBLT) { order_flags |= RDP_ORDER_CHANGE; } self->orders_state.last_order = RDP_ORDER_SCREENBLT; if (rect != 0) { /* if clip is present, still check if its needed */ if (x < rect->left || y < rect->top || x + cx > rect->right || y + cy > rect->bottom) { order_flags |= RDP_ORDER_BOUNDS; if (xrdp_orders_last_bounds(self, rect)) { order_flags |= RDP_ORDER_LASTBOUNDS; } } } vals[0] = x; vals[1] = self->orders_state.scr_blt_x; vals[2] = y; vals[3] = self->orders_state.scr_blt_y; vals[4] = cx; vals[5] = self->orders_state.scr_blt_cx; vals[6] = cy; vals[7] = self->orders_state.scr_blt_cy; vals[8] = srcx; vals[9] = self->orders_state.scr_blt_srcx; vals[10] = srcy; vals[11] = self->orders_state.scr_blt_srcy; if (xrdp_orders_send_delta(self, vals, 12)) { order_flags |= RDP_ORDER_DELTA; } /* order_flags, set later, 1 byte */ order_flags_ptr = self->out_s->p; out_uint8s(self->out_s, 1); if (order_flags & RDP_ORDER_CHANGE) { out_uint8(self->out_s, self->orders_state.last_order); } present = 0; /* present, set later, 1 byte */ present_ptr = self->out_s->p; out_uint8s(self->out_s, 1); if ((order_flags & RDP_ORDER_BOUNDS) && !(order_flags & RDP_ORDER_LASTBOUNDS)) { xrdp_orders_out_bounds(self, rect); } if (x != self->orders_state.scr_blt_x) { present |= 0x01; if (order_flags & RDP_ORDER_DELTA) { out_uint8(self->out_s, x - self->orders_state.scr_blt_x); } else { out_uint16_le(self->out_s, x); } self->orders_state.scr_blt_x = x; } if (y != self->orders_state.scr_blt_y) { present |= 0x02; if (order_flags & RDP_ORDER_DELTA) { out_uint8(self->out_s, y - self->orders_state.scr_blt_y); } else { out_uint16_le(self->out_s, y); } self->orders_state.scr_blt_y = y; } if (cx != self->orders_state.scr_blt_cx) { present |= 0x04; if (order_flags & RDP_ORDER_DELTA) { out_uint8(self->out_s, cx - self->orders_state.scr_blt_cx); } else { out_uint16_le(self->out_s, cx); } self->orders_state.scr_blt_cx = cx; } if (cy != self->orders_state.scr_blt_cy) { present |= 0x08; if (order_flags & RDP_ORDER_DELTA) { out_uint8(self->out_s, cy - self->orders_state.scr_blt_cy); } else { out_uint16_le(self->out_s, cy); } self->orders_state.scr_blt_cy = cy; } if (rop != self->orders_state.scr_blt_rop) { present |= 0x10; out_uint8(self->out_s, rop); self->orders_state.scr_blt_rop = rop; } if (srcx != self->orders_state.scr_blt_srcx) { present |= 0x20; if (order_flags & RDP_ORDER_DELTA) { out_uint8(self->out_s, srcx - self->orders_state.scr_blt_srcx); } else { out_uint16_le(self->out_s, srcx); } self->orders_state.scr_blt_srcx = srcx; } if (srcy != self->orders_state.scr_blt_srcy) { present |= 0x40; if (order_flags & RDP_ORDER_DELTA) { out_uint8(self->out_s, srcy - self->orders_state.scr_blt_srcy); } else { out_uint16_le(self->out_s, srcy); } self->orders_state.scr_blt_srcy = srcy; } xrdp_order_pack_small_or_tiny(self, order_flags_ptr, order_flags, present_ptr, present, 1); return 0; } /*****************************************************************************/ /* returns error */ /* send a pat blt order */ /* max size 39 */ int APP_CC xrdp_orders_pat_blt(struct xrdp_orders* self, int x, int y, int cx, int cy, int rop, int bg_color, int fg_color, struct xrdp_brush* brush, struct xrdp_rect* rect) { int order_flags; int present; int vals[8]; char* present_ptr; char* order_flags_ptr; struct xrdp_brush blank_brush; xrdp_orders_check(self, 39); self->order_count++; order_flags = RDP_ORDER_STANDARD; if (self->orders_state.last_order != RDP_ORDER_PATBLT) { order_flags |= RDP_ORDER_CHANGE; } self->orders_state.last_order = RDP_ORDER_PATBLT; if (rect != 0) { /* if clip is present, still check if its needed */ if (x < rect->left || y < rect->top || x + cx > rect->right || y + cy > rect->bottom) { order_flags |= RDP_ORDER_BOUNDS; if (xrdp_orders_last_bounds(self, rect)) { order_flags |= RDP_ORDER_LASTBOUNDS; } } } vals[0] = x; vals[1] = self->orders_state.pat_blt_x; vals[2] = y; vals[3] = self->orders_state.pat_blt_y; vals[4] = cx; vals[5] = self->orders_state.pat_blt_cx; vals[6] = cy; vals[7] = self->orders_state.pat_blt_cy; if (xrdp_orders_send_delta(self, vals, 8)) { order_flags |= RDP_ORDER_DELTA; } /* order_flags, set later, 1 byte */ order_flags_ptr = self->out_s->p; out_uint8s(self->out_s, 1); if (order_flags & RDP_ORDER_CHANGE) { out_uint8(self->out_s, self->orders_state.last_order); } present = 0; /* present, set later, 2 bytes */ present_ptr = self->out_s->p; out_uint8s(self->out_s, 2); if ((order_flags & RDP_ORDER_BOUNDS) && !(order_flags & RDP_ORDER_LASTBOUNDS)) { xrdp_orders_out_bounds(self, rect); } if (x != self->orders_state.pat_blt_x) { present |= 0x0001; if (order_flags & RDP_ORDER_DELTA) { out_uint8(self->out_s, x - self->orders_state.pat_blt_x); } else { out_uint16_le(self->out_s, x); } self->orders_state.pat_blt_x = x; } if (y != self->orders_state.pat_blt_y) { present |= 0x0002; if (order_flags & RDP_ORDER_DELTA) { out_uint8(self->out_s, y - self->orders_state.pat_blt_y); } else { out_uint16_le(self->out_s, y); } self->orders_state.pat_blt_y = y; } if (cx != self->orders_state.pat_blt_cx) { present |= 0x0004; if (order_flags & RDP_ORDER_DELTA) { out_uint8(self->out_s, cx - self->orders_state.pat_blt_cx); } else { out_uint16_le(self->out_s, cx); } self->orders_state.pat_blt_cx = cx; } if (cy != self->orders_state.pat_blt_cy) { present |= 0x0008; if (order_flags & RDP_ORDER_DELTA) { out_uint8(self->out_s, cy - self->orders_state.pat_blt_cy); } else { out_uint16_le(self->out_s, cy); } self->orders_state.pat_blt_cy = cy; } if (rop != self->orders_state.pat_blt_rop) { present |= 0x0010; /* PATCOPY PATPAINT PATINVERT DSTINVERT BLACKNESS WHITENESS */ out_uint8(self->out_s, rop); self->orders_state.pat_blt_rop = rop; } if (bg_color != self->orders_state.pat_blt_bg_color) { present |= 0x0020; out_uint8(self->out_s, bg_color); out_uint8(self->out_s, bg_color >> 8); out_uint8(self->out_s, bg_color >> 16); self->orders_state.pat_blt_bg_color = bg_color; } if (fg_color != self->orders_state.pat_blt_fg_color) { present |= 0x0040; out_uint8(self->out_s, fg_color); out_uint8(self->out_s, fg_color >> 8); out_uint8(self->out_s, fg_color >> 16); self->orders_state.pat_blt_fg_color = fg_color; } if (brush == 0) /* if nil use blank one */ { /* todo can we just set style to zero */ g_memset(&blank_brush, 0, sizeof(struct xrdp_brush)); brush = &blank_brush; } if (brush->x_orgin != self->orders_state.pat_blt_brush.x_orgin) { present |= 0x0080; out_uint8(self->out_s, brush->x_orgin); self->orders_state.pat_blt_brush.x_orgin = brush->x_orgin; } if (brush->y_orgin != self->orders_state.pat_blt_brush.y_orgin) { present |= 0x0100; out_uint8(self->out_s, brush->y_orgin); self->orders_state.pat_blt_brush.y_orgin = brush->y_orgin; } if (brush->style != self->orders_state.pat_blt_brush.style) { present |= 0x0200; out_uint8(self->out_s, brush->style); self->orders_state.pat_blt_brush.style = brush->style; } if (brush->pattern[0] != self->orders_state.pat_blt_brush.pattern[0]) { present |= 0x0400; out_uint8(self->out_s, brush->pattern[0]); self->orders_state.pat_blt_brush.pattern[0] = brush->pattern[0]; } if (g_memcmp(brush->pattern + 1, self->orders_state.pat_blt_brush.pattern + 1, 7) != 0) { present |= 0x0800; out_uint8a(self->out_s, brush->pattern + 1, 7); g_memcpy(self->orders_state.pat_blt_brush.pattern + 1, brush->pattern + 1, 7); } xrdp_order_pack_small_or_tiny(self, order_flags_ptr, order_flags, present_ptr, present, 2); return 0; } /*****************************************************************************/ /* returns error */ /* send a dest blt order */ /* max size 21 */ int APP_CC xrdp_orders_dest_blt(struct xrdp_orders* self, int x, int y, int cx, int cy, int rop, struct xrdp_rect* rect) { int order_flags; int vals[8]; int present; char* present_ptr; char* order_flags_ptr; xrdp_orders_check(self, 21); self->order_count++; order_flags = RDP_ORDER_STANDARD; if (self->orders_state.last_order != RDP_ORDER_DESTBLT) { order_flags |= RDP_ORDER_CHANGE; } self->orders_state.last_order = RDP_ORDER_DESTBLT; if (rect != 0) { /* if clip is present, still check if its needed */ if (x < rect->left || y < rect->top || x + cx > rect->right || y + cy > rect->bottom) { order_flags |= RDP_ORDER_BOUNDS; if (xrdp_orders_last_bounds(self, rect)) { order_flags |= RDP_ORDER_LASTBOUNDS; } } } vals[0] = x; vals[1] = self->orders_state.dest_blt_x; vals[2] = y; vals[3] = self->orders_state.dest_blt_y; vals[4] = cx; vals[5] = self->orders_state.dest_blt_cx; vals[6] = cy; vals[7] = self->orders_state.dest_blt_cy; if (xrdp_orders_send_delta(self, vals, 8)) { order_flags |= RDP_ORDER_DELTA; } /* order_flags, set later, 1 byte */ order_flags_ptr = self->out_s->p; out_uint8s(self->out_s, 1); if (order_flags & RDP_ORDER_CHANGE) { out_uint8(self->out_s, self->orders_state.last_order); } present = 0; /* present, set later, 1 byte */ present_ptr = self->out_s->p; out_uint8s(self->out_s, 1); if ((order_flags & RDP_ORDER_BOUNDS) && !(order_flags & RDP_ORDER_LASTBOUNDS)) { xrdp_orders_out_bounds(self, rect); } if (x != self->orders_state.dest_blt_x) { present |= 0x01; if (order_flags & RDP_ORDER_DELTA) { out_uint8(self->out_s, x - self->orders_state.dest_blt_x); } else { out_uint16_le(self->out_s, x); } self->orders_state.dest_blt_x = x; } if (y != self->orders_state.dest_blt_y) { present |= 0x02; if (order_flags & RDP_ORDER_DELTA) { out_uint8(self->out_s, y - self->orders_state.dest_blt_y); } else { out_uint16_le(self->out_s, y); } self->orders_state.dest_blt_y = y; } if (cx != self->orders_state.dest_blt_cx) { present |= 0x04; if (order_flags & RDP_ORDER_DELTA) { out_uint8(self->out_s, cx - self->orders_state.dest_blt_cx); } else { out_uint16_le(self->out_s, cx); } self->orders_state.dest_blt_cx = cx; } if (cy != self->orders_state.dest_blt_cy) { present |= 0x08; if (order_flags & RDP_ORDER_DELTA) { out_uint8(self->out_s, cy - self->orders_state.dest_blt_cy); } else { out_uint16_le(self->out_s, cy); } self->orders_state.dest_blt_cy = cy; } if (rop != self->orders_state.dest_blt_rop) { present |= 0x10; out_uint8(self->out_s, rop); self->orders_state.dest_blt_rop = rop; } xrdp_order_pack_small_or_tiny(self, order_flags_ptr, order_flags, present_ptr, present, 1); return 0; } /*****************************************************************************/ /* returns error */ /* send a line order */ /* max size 32 */ int APP_CC xrdp_orders_line(struct xrdp_orders* self, int mix_mode, int startx, int starty, int endx, int endy, int rop, int bg_color, struct xrdp_pen* pen, struct xrdp_rect* rect) { int order_flags = 0; int vals[8] = {0, 0, 0, 0, 0, 0, 0, 0}; int present = 0; char* present_ptr = (char *)NULL; char* order_flags_ptr = (char *)NULL; struct xrdp_pen blank_pen; g_memset(&blank_pen,0,sizeof(struct xrdp_pen)); /* if mix mode or rop are out of range, mstsc build 6000+ will parse the orders wrong */ if ((mix_mode < 1) || (mix_mode > 2)) /* TRANSPARENT(1) or OPAQUE(2) */ { mix_mode = 1; } if ((rop < 1) || (rop > 0x10)) { rop = 0x0d; /* R2_COPYPEN */ } xrdp_orders_check(self, 32); self->order_count++; order_flags = RDP_ORDER_STANDARD; if (self->orders_state.last_order != RDP_ORDER_LINE) { order_flags |= RDP_ORDER_CHANGE; } self->orders_state.last_order = RDP_ORDER_LINE; if (rect != 0) { /* if clip is present, still check if its needed */ if (MIN(endx, startx) < rect->left || MIN(endy, starty) < rect->top || MAX(endx, startx) >= rect->right || MAX(endy, starty) >= rect->bottom) { order_flags |= RDP_ORDER_BOUNDS; if (xrdp_orders_last_bounds(self, rect)) { order_flags |= RDP_ORDER_LASTBOUNDS; } } } vals[0] = startx; vals[1] = self->orders_state.line_startx; vals[2] = starty; vals[3] = self->orders_state.line_starty; vals[4] = endx; vals[5] = self->orders_state.line_endx; vals[6] = endy; vals[7] = self->orders_state.line_endy; if (xrdp_orders_send_delta(self, vals, 8)) { order_flags |= RDP_ORDER_DELTA; } /* order_flags, set later, 1 byte */ order_flags_ptr = self->out_s->p; out_uint8s(self->out_s, 1); if (order_flags & RDP_ORDER_CHANGE) { out_uint8(self->out_s, self->orders_state.last_order); } present = 0; /* present, set later, 2 bytes */ present_ptr = self->out_s->p; out_uint8s(self->out_s, 2); if ((order_flags & RDP_ORDER_BOUNDS) && !(order_flags & RDP_ORDER_LASTBOUNDS)) { xrdp_orders_out_bounds(self, rect); } if (mix_mode != self->orders_state.line_mix_mode) { present |= 0x0001; out_uint16_le(self->out_s, mix_mode); self->orders_state.line_mix_mode = mix_mode; } if (startx != self->orders_state.line_startx) { present |= 0x0002; if (order_flags & RDP_ORDER_DELTA) { out_uint8(self->out_s, startx - self->orders_state.line_startx); } else { out_uint16_le(self->out_s, startx); } self->orders_state.line_startx = startx; } if (starty != self->orders_state.line_starty) { present |= 0x0004; if (order_flags & RDP_ORDER_DELTA) { out_uint8(self->out_s, starty - self->orders_state.line_starty); } else { out_uint16_le(self->out_s, starty); } self->orders_state.line_starty = starty; } if (endx != self->orders_state.line_endx) { present |= 0x0008; if (order_flags & RDP_ORDER_DELTA) { out_uint8(self->out_s, endx - self->orders_state.line_endx); } else { out_uint16_le(self->out_s, endx); } self->orders_state.line_endx = endx; } if (endy != self->orders_state.line_endy) { present |= 0x0010; if (order_flags & RDP_ORDER_DELTA) { out_uint8(self->out_s, endy - self->orders_state.line_endy); } else { out_uint16_le(self->out_s, endy); } self->orders_state.line_endy = endy; } if (bg_color != self->orders_state.line_bg_color) { present |= 0x0020; out_uint8(self->out_s, bg_color); out_uint8(self->out_s, bg_color >> 8); out_uint8(self->out_s, bg_color >> 16); self->orders_state.line_bg_color = bg_color; } if (rop != self->orders_state.line_rop) { present |= 0x0040; out_uint8(self->out_s, rop); self->orders_state.line_rop = rop; } if (pen == 0) { g_memset(&blank_pen, 0, sizeof(struct xrdp_pen)); pen = &blank_pen; } if (pen->style != self->orders_state.line_pen.style) { present |= 0x0080; out_uint8(self->out_s, pen->style); self->orders_state.line_pen.style = pen->style; } if (pen->width != self->orders_state.line_pen.width) { present |= 0x0100; out_uint8(self->out_s, pen->width); self->orders_state.line_pen.width = pen->width; } if (pen->color != self->orders_state.line_pen.color) { present |= 0x0200; out_uint8(self->out_s, pen->color); out_uint8(self->out_s, pen->color >> 8); out_uint8(self->out_s, pen->color >> 16); self->orders_state.line_pen.color = pen->color; } xrdp_order_pack_small_or_tiny(self, order_flags_ptr, order_flags, present_ptr, present, 2); return 0; } /*****************************************************************************/ /* returns error */ /* send a mem blt order */ /* max size 30 */ int APP_CC xrdp_orders_mem_blt(struct xrdp_orders* self, int cache_id, int color_table, int x, int y, int cx, int cy, int rop, int srcx, int srcy, int cache_idx, struct xrdp_rect* rect) { int order_flags = 0; int vals[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; int present = 0; char* present_ptr = (char *)NULL; char* order_flags_ptr = (char *)NULL; xrdp_orders_check(self, 30); self->order_count++; order_flags = RDP_ORDER_STANDARD; if (self->orders_state.last_order != RDP_ORDER_MEMBLT) { order_flags |= RDP_ORDER_CHANGE; } self->orders_state.last_order = RDP_ORDER_MEMBLT; if (rect != 0) { /* if clip is present, still check if its needed */ if (x < rect->left || y < rect->top || x + cx > rect->right || y + cy > rect->bottom) { order_flags |= RDP_ORDER_BOUNDS; if (xrdp_orders_last_bounds(self, rect)) { order_flags |= RDP_ORDER_LASTBOUNDS; } } } vals[0] = x; vals[1] = self->orders_state.mem_blt_x; vals[2] = y; vals[3] = self->orders_state.mem_blt_y; vals[4] = cx; vals[5] = self->orders_state.mem_blt_cx; vals[6] = cy; vals[7] = self->orders_state.mem_blt_cy; vals[8] = srcx; vals[9] = self->orders_state.mem_blt_srcx; vals[10] = srcy; vals[11] = self->orders_state.mem_blt_srcy; if (xrdp_orders_send_delta(self, vals, 12)) { order_flags |= RDP_ORDER_DELTA; } /* order_flags, set later, 1 byte */ order_flags_ptr = self->out_s->p; out_uint8s(self->out_s, 1); if (order_flags & RDP_ORDER_CHANGE) { out_uint8(self->out_s, self->orders_state.last_order); } present = 0; /* present, set later, 2 bytes */ present_ptr = self->out_s->p; out_uint8s(self->out_s, 2); if ((order_flags & RDP_ORDER_BOUNDS) && !(order_flags & RDP_ORDER_LASTBOUNDS)) { xrdp_orders_out_bounds(self, rect); } if (cache_id != self->orders_state.mem_blt_cache_id || color_table != self->orders_state.mem_blt_color_table) { present |= 0x0001; out_uint8(self->out_s, cache_id); out_uint8(self->out_s, color_table); self->orders_state.mem_blt_cache_id = cache_id; self->orders_state.mem_blt_color_table = color_table; } if (x != self->orders_state.mem_blt_x) { present |= 0x0002; if (order_flags & RDP_ORDER_DELTA) { out_uint8(self->out_s, x - self->orders_state.mem_blt_x); } else { out_uint16_le(self->out_s, x); } self->orders_state.mem_blt_x = x; } if (y != self->orders_state.mem_blt_y) { present |= 0x0004; if (order_flags & RDP_ORDER_DELTA) { out_uint8(self->out_s, y - self->orders_state.mem_blt_y); } else { out_uint16_le(self->out_s, y); } self->orders_state.mem_blt_y = y; } if (cx != self->orders_state.mem_blt_cx) { present |= 0x0008; if (order_flags & RDP_ORDER_DELTA) { out_uint8(self->out_s, cx - self->orders_state.mem_blt_cx); } else { out_uint16_le(self->out_s, cx); } self->orders_state.mem_blt_cx = cx; } if (cy != self->orders_state.mem_blt_cy) { present |= 0x0010; if (order_flags & RDP_ORDER_DELTA) { out_uint8(self->out_s, cy - self->orders_state.mem_blt_cy); } else { out_uint16_le(self->out_s, cy); } self->orders_state.mem_blt_cy = cy; } if (rop != self->orders_state.mem_blt_rop) { present |= 0x0020; out_uint8(self->out_s, rop); self->orders_state.mem_blt_rop = rop; } if (srcx != self->orders_state.mem_blt_srcx) { present |= 0x0040; if (order_flags & RDP_ORDER_DELTA) { out_uint8(self->out_s, srcx - self->orders_state.mem_blt_srcx); } else { out_uint16_le(self->out_s, srcx); } self->orders_state.mem_blt_srcx = srcx; } if (srcy != self->orders_state.mem_blt_srcy) { present |= 0x0080; if (order_flags & RDP_ORDER_DELTA) { out_uint8(self->out_s, srcy - self->orders_state.mem_blt_srcy); } else { out_uint16_le(self->out_s, srcy); } self->orders_state.mem_blt_srcy = srcy; } if (cache_idx != self->orders_state.mem_blt_cache_idx) { present |= 0x0100; out_uint16_le(self->out_s, cache_idx); self->orders_state.mem_blt_cache_idx = cache_idx; } xrdp_order_pack_small_or_tiny(self, order_flags_ptr, order_flags, present_ptr, present, 2); return 0; } /*****************************************************************************/ /* returns error */ int APP_CC xrdp_orders_text(struct xrdp_orders* self, int font, int flags, int mixmode, int fg_color, int bg_color, int clip_left, int clip_top, int clip_right, int clip_bottom, int box_left, int box_top, int box_right, int box_bottom, int x, int y, char* data, int data_len, struct xrdp_rect* rect) { int order_flags = 0; int present = 0; char* present_ptr = (char *)NULL; char* order_flags_ptr = (char *)NULL; xrdp_orders_check(self, 100); self->order_count++; order_flags = RDP_ORDER_STANDARD; if (self->orders_state.last_order != RDP_ORDER_TEXT2) { order_flags |= RDP_ORDER_CHANGE; } self->orders_state.last_order = RDP_ORDER_TEXT2; if (rect != 0) { /* if clip is present, still check if its needed */ if ((box_right - box_left > 1 && (box_left < rect->left || box_top < rect->top || box_right > rect->right || box_bottom > rect->bottom)) || (clip_left < rect->left || clip_top < rect->top || clip_right > rect->right || clip_bottom > rect->bottom)) { order_flags |= RDP_ORDER_BOUNDS; if (xrdp_orders_last_bounds(self, rect)) { order_flags |= RDP_ORDER_LASTBOUNDS; } } } /* order_flags, set later, 1 byte */ order_flags_ptr = self->out_s->p; out_uint8s(self->out_s, 1); if (order_flags & RDP_ORDER_CHANGE) { out_uint8(self->out_s, self->orders_state.last_order); } present = 0; /* present, set later, 3 bytes */ present_ptr = self->out_s->p; out_uint8s(self->out_s, 3); if ((order_flags & RDP_ORDER_BOUNDS) && !(order_flags & RDP_ORDER_LASTBOUNDS)) { xrdp_orders_out_bounds(self, rect); } if (font != self->orders_state.text_font) { present |= 0x000001; out_uint8(self->out_s, font); self->orders_state.text_font = font; } if (flags != self->orders_state.text_flags) { present |= 0x000002; out_uint8(self->out_s, flags); self->orders_state.text_flags = flags; } /* unknown */ if (mixmode != self->orders_state.text_mixmode) { present |= 0x000008; out_uint8(self->out_s, mixmode); self->orders_state.text_mixmode = mixmode; } if (fg_color != self->orders_state.text_fg_color) { present |= 0x000010; out_uint8(self->out_s, fg_color); out_uint8(self->out_s, fg_color >> 8); out_uint8(self->out_s, fg_color >> 16); self->orders_state.text_fg_color = fg_color; } if (bg_color != self->orders_state.text_bg_color) { present |= 0x000020; out_uint8(self->out_s, bg_color); out_uint8(self->out_s, bg_color >> 8); out_uint8(self->out_s, bg_color >> 16); self->orders_state.text_bg_color = bg_color; } if (clip_left != self->orders_state.text_clip_left) { present |= 0x000040; out_uint16_le(self->out_s, clip_left); self->orders_state.text_clip_left = clip_left; } if (clip_top != self->orders_state.text_clip_top) { present |= 0x000080; out_uint16_le(self->out_s, clip_top); self->orders_state.text_clip_top = clip_top; } if (clip_right != self->orders_state.text_clip_right) { present |= 0x000100; out_uint16_le(self->out_s, clip_right); self->orders_state.text_clip_right = clip_right; } if (clip_bottom != self->orders_state.text_clip_bottom) { present |= 0x000200; out_uint16_le(self->out_s, clip_bottom); self->orders_state.text_clip_bottom = clip_bottom; } if (box_left != self->orders_state.text_box_left) { present |= 0x000400; out_uint16_le(self->out_s, box_left); self->orders_state.text_box_left = box_left; } if (box_top != self->orders_state.text_box_top) { present |= 0x000800; out_uint16_le(self->out_s, box_top); self->orders_state.text_box_top = box_top; } if (box_right != self->orders_state.text_box_right) { present |= 0x001000; out_uint16_le(self->out_s, box_right); self->orders_state.text_box_right = box_right; } if (box_bottom != self->orders_state.text_box_bottom) { present |= 0x002000; out_uint16_le(self->out_s, box_bottom); self->orders_state.text_box_bottom = box_bottom; } if (x != self->orders_state.text_x) { present |= 0x080000; out_uint16_le(self->out_s, x); self->orders_state.text_x = x; } if (y != self->orders_state.text_y) { present |= 0x100000; out_uint16_le(self->out_s, y); self->orders_state.text_y = y; } { /* always send text */ present |= 0x200000; out_uint8(self->out_s, data_len); out_uint8a(self->out_s, data, data_len); } xrdp_order_pack_small_or_tiny(self, order_flags_ptr, order_flags, present_ptr, present, 3); return 0; } /*****************************************************************************/ /* returns error */ /* when a palette gets sent, send the main palette too */ int APP_CC xrdp_orders_send_palette(struct xrdp_orders* self, int* palette, int cache_id) { int order_flags; int len; int i; xrdp_orders_check(self, 2000); self->order_count++; order_flags = RDP_ORDER_STANDARD | RDP_ORDER_SECONDARY; out_uint8(self->out_s, order_flags); len = 1027 - 7; /* length after type minus 7 */ out_uint16_le(self->out_s, len); out_uint16_le(self->out_s, 0); /* flags */ out_uint8(self->out_s, RDP_ORDER_COLCACHE); /* type */ out_uint8(self->out_s, cache_id); out_uint16_le(self->out_s, 256); /* num colors */ for (i = 0; i < 256; i++) { out_uint8(self->out_s, palette[i]); out_uint8(self->out_s, palette[i] >> 8); out_uint8(self->out_s, palette[i] >> 16); out_uint8(self->out_s, 0); } return 0; } /*****************************************************************************/ /* returns error */ /* max size width * height * Bpp + 16 */ int APP_CC xrdp_orders_send_raw_bitmap(struct xrdp_orders* self, int width, int height, int bpp, char* data, int cache_id, int cache_idx) { int order_flags = 0; int len = 0; int bufsize = 0; int Bpp = 0; int i = 0; int j = 0; int pixel = 0; int e = 0; if (width > 64) { g_writeln("error, width > 64"); return 1; } if (height > 64) { g_writeln("error, height > 64"); return 1; } e = width % 4; if (e != 0) { e = 4 - e; } Bpp = (bpp + 7) / 8; bufsize = (width + e) * height * Bpp; xrdp_orders_check(self, bufsize + 16); self->order_count++; order_flags = RDP_ORDER_STANDARD | RDP_ORDER_SECONDARY; out_uint8(self->out_s, order_flags); len = (bufsize + 9) - 7; /* length after type minus 7 */ out_uint16_le(self->out_s, len); out_uint16_le(self->out_s, 8); /* flags */ out_uint8(self->out_s, RDP_ORDER_RAW_BMPCACHE); /* type */ out_uint8(self->out_s, cache_id); out_uint8s(self->out_s, 1); /* pad */ out_uint8(self->out_s, width + e); out_uint8(self->out_s, height); out_uint8(self->out_s, bpp); out_uint16_le(self->out_s, bufsize); out_uint16_le(self->out_s, cache_idx); for (i = height - 1; i >= 0; i--) { for (j = 0; j < width; j++) { if (Bpp == 3) { pixel = GETPIXEL32(data, j, i, width); out_uint8(self->out_s, pixel >> 16); out_uint8(self->out_s, pixel >> 8); out_uint8(self->out_s, pixel); } else if (Bpp == 2) { pixel = GETPIXEL16(data, j, i, width); out_uint8(self->out_s, pixel); out_uint8(self->out_s, pixel >> 8); } else if (Bpp == 1) { pixel = GETPIXEL8(data, j, i, width); out_uint8(self->out_s, pixel); } } for (j = 0; j < e; j++) { out_uint8s(self->out_s, Bpp); } } return 0; } /*****************************************************************************/ /* returns error */ /* max size width * height * Bpp + 16 */ int APP_CC xrdp_orders_send_bitmap(struct xrdp_orders* self, int width, int height, int bpp, char* data, int cache_id, int cache_idx) { int order_flags = 0; int len = 0; int bufsize = 0; int Bpp = 0; int i = 0; int lines_sending = 0; int e = 0; struct stream* s = NULL; struct stream* temp_s = NULL; char* p = NULL; if (width > 64) { g_writeln("error, width > 64"); return 1; } if (height > 64) { g_writeln("error, height > 64"); return 1; } e = width % 4; if (e != 0) { e = 4 - e; } make_stream(s); init_stream(s, 16384); make_stream(temp_s); init_stream(temp_s, 16384); p = s->p; i = height; lines_sending = xrdp_bitmap_compress(data, width, height, s, bpp, 16384, i - 1, temp_s, e); if (lines_sending != height) { free_stream(s); free_stream(temp_s); g_writeln("error in xrdp_orders_send_bitmap, lines_sending(%d) != \ height(%d)", lines_sending, height); return 1; } bufsize = (int)(s->p - p); Bpp = (bpp + 7) / 8; xrdp_orders_check(self, bufsize + 16); self->order_count++; order_flags = RDP_ORDER_STANDARD | RDP_ORDER_SECONDARY; out_uint8(self->out_s, order_flags); if (self->rdp_layer->client_info.op2) { len = (bufsize + 9) - 7; /* length after type minus 7 */ out_uint16_le(self->out_s, len); out_uint16_le(self->out_s, 1024); /* flags */ } else { len = (bufsize + 9 + 8) - 7; /* length after type minus 7 */ out_uint16_le(self->out_s, len); out_uint16_le(self->out_s, 8); /* flags */ } out_uint8(self->out_s, RDP_ORDER_BMPCACHE); /* type */ out_uint8(self->out_s, cache_id); out_uint8s(self->out_s, 1); /* pad */ out_uint8(self->out_s, width + e); out_uint8(self->out_s, height); out_uint8(self->out_s, bpp); out_uint16_le(self->out_s, bufsize/* + 8*/); out_uint16_le(self->out_s, cache_idx); if (!self->rdp_layer->client_info.op2) { out_uint8s(self->out_s, 2); /* pad */ out_uint16_le(self->out_s, bufsize); out_uint16_le(self->out_s, (width + e) * Bpp); /* line size */ out_uint16_le(self->out_s, (width + e) * Bpp * height); /* final size */ } out_uint8a(self->out_s, s->data, bufsize); free_stream(s); free_stream(temp_s); return 0; } /*****************************************************************************/ /* returns error */ /* max size datasize + 18*/ /* todo, only sends one for now */ int APP_CC xrdp_orders_send_font(struct xrdp_orders* self, struct xrdp_font_char* font_char, int font_index, int char_index) { int order_flags = 0; int datasize = 0; int len = 0; datasize = FONT_DATASIZE(font_char); xrdp_orders_check(self, datasize + 18); self->order_count++; order_flags = RDP_ORDER_STANDARD | RDP_ORDER_SECONDARY; out_uint8(self->out_s, order_flags); len = (datasize + 12) - 7; /* length after type minus 7 */ out_uint16_le(self->out_s, len); out_uint16_le(self->out_s, 8); /* flags */ out_uint8(self->out_s, RDP_ORDER_FONTCACHE); /* type */ out_uint8(self->out_s, font_index); out_uint8(self->out_s, 1); /* num of chars */ out_uint16_le(self->out_s, char_index); out_uint16_le(self->out_s, font_char->offset); out_uint16_le(self->out_s, font_char->baseline); out_uint16_le(self->out_s, font_char->width); out_uint16_le(self->out_s, font_char->height); out_uint8a(self->out_s, font_char->data, datasize); return 0; } /*****************************************************************************/ /* returns error */ /* max size width * height * Bpp + 14 */ int APP_CC xrdp_orders_send_raw_bitmap2(struct xrdp_orders* self, int width, int height, int bpp, char* data, int cache_id, int cache_idx) { int order_flags = 0; int len = 0; int bufsize = 0; int Bpp = 0; int i = 0; int j = 0; int pixel = 0; int e = 0; if (width > 64) { g_writeln("error, width > 64"); return 1; } if (height > 64) { g_writeln("error, height > 64"); return 1; } e = width % 4; if (e != 0) { e = 4 - e; } Bpp = (bpp + 7) / 8; bufsize = (width + e) * height * Bpp; xrdp_orders_check(self, bufsize + 14); self->order_count++; order_flags = RDP_ORDER_STANDARD | RDP_ORDER_SECONDARY; out_uint8(self->out_s, order_flags); len = (bufsize + 6) - 7; /* length after type minus 7 */ out_uint16_le(self->out_s, len); i = (((Bpp + 2) << 3) & 0x38) | (cache_id & 7); out_uint16_le(self->out_s, i); /* flags */ out_uint8(self->out_s, RDP_ORDER_RAW_BMPCACHE2); /* type */ out_uint8(self->out_s, width + e); out_uint8(self->out_s, height); out_uint16_be(self->out_s, bufsize | 0x4000); i = ((cache_idx >> 8) & 0xff) | 0x80; out_uint8(self->out_s, i); i = cache_idx & 0xff; out_uint8(self->out_s, i); for (i = height - 1; i >= 0; i--) { for (j = 0; j < width; j++) { if (Bpp == 3) { pixel = GETPIXEL32(data, j, i, width); out_uint8(self->out_s, pixel >> 16); out_uint8(self->out_s, pixel >> 8); out_uint8(self->out_s, pixel); } else if (Bpp == 2) { pixel = GETPIXEL16(data, j, i, width); out_uint8(self->out_s, pixel); out_uint8(self->out_s, pixel >> 8); } else if (Bpp == 1) { pixel = GETPIXEL8(data, j, i, width); out_uint8(self->out_s, pixel); } } for (j = 0; j < e; j++) { out_uint8s(self->out_s, Bpp); } } return 0; } /*****************************************************************************/ /* returns error */ /* max size width * height * Bpp + 14 */ int APP_CC xrdp_orders_send_bitmap2(struct xrdp_orders* self, int width, int height, int bpp, char* data, int cache_id, int cache_idx) { int order_flags = 0; int len = 0; int bufsize = 0; int Bpp = 0; int i = 0; int lines_sending = 0; int e = 0; struct stream* s = NULL; struct stream* temp_s = NULL; char* p = NULL; if (width > 64) { g_writeln("error, width > 64"); return 1; } if (height > 64) { g_writeln("error, height > 64"); return 1; } e = width % 4; if (e != 0) { e = 4 - e; } make_stream(s); init_stream(s, 16384); make_stream(temp_s); init_stream(temp_s, 16384); p = s->p; i = height; lines_sending = xrdp_bitmap_compress(data, width, height, s, bpp, 16384, i - 1, temp_s, e); if (lines_sending != height) { free_stream(s); free_stream(temp_s); g_writeln("error in xrdp_orders_send_bitmap2, lines_sending(%d) != \ height(%d)", lines_sending, height); return 1; } bufsize = (int)(s->p - p); Bpp = (bpp + 7) / 8; xrdp_orders_check(self, bufsize + 14); self->order_count++; order_flags = RDP_ORDER_STANDARD | RDP_ORDER_SECONDARY; out_uint8(self->out_s, order_flags); len = (bufsize + 6) - 7; /* length after type minus 7 */ out_uint16_le(self->out_s, len); i = (((Bpp + 2) << 3) & 0x38) | (cache_id & 7); i = i | 0x400; out_uint16_le(self->out_s, i); /* flags */ out_uint8(self->out_s, RDP_ORDER_BMPCACHE2); /* type */ out_uint8(self->out_s, width + e); out_uint8(self->out_s, height); out_uint16_be(self->out_s, bufsize | 0x4000); i = ((cache_idx >> 8) & 0xff) | 0x80; out_uint8(self->out_s, i); i = cache_idx & 0xff; out_uint8(self->out_s, i); out_uint8a(self->out_s, s->data, bufsize); free_stream(s); free_stream(temp_s); return 0; } /*****************************************************************************/ /* returns error */ /* send a brush cache entry */ int APP_CC xrdp_orders_send_brush(struct xrdp_orders* self, int width, int height, int bpp, int type, int size, char* data, int cache_id) { int order_flags = 0; int len = 0; xrdp_orders_check(self, size + 12); self->order_count++; order_flags = RDP_ORDER_STANDARD | RDP_ORDER_SECONDARY; out_uint8(self->out_s, order_flags); len = (size + 6) - 7; /* length after type minus 7 */ out_uint16_le(self->out_s, len); out_uint16_le(self->out_s, 0); /* flags */ out_uint8(self->out_s, RDP_ORDER_BRUSHCACHE); /* type */ out_uint8(self->out_s, cache_id); out_uint8(self->out_s, bpp); out_uint8(self->out_s, width); out_uint8(self->out_s, height); out_uint8(self->out_s, type); out_uint8(self->out_s, size); out_uint8a(self->out_s, data, size); return 0; } xrdp-0.6.0/libxrdp/xrdp_rdp.c000066400000000000000000001013501203155130500161170ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2004-2010 rdp layer */ #include "libxrdp.h" /* some compilers need unsigned char to avoid warnings */ static tui8 g_unknown1[172] = { 0xff, 0x02, 0xb6, 0x00, 0x28, 0x00, 0x00, 0x00, 0x27, 0x00, 0x27, 0x00, 0x03, 0x00, 0x04, 0x00, 0x00, 0x00, 0x26, 0x00, 0x01, 0x00, 0x1e, 0x00, 0x02, 0x00, 0x1f, 0x00, 0x03, 0x00, 0x1d, 0x00, 0x04, 0x00, 0x27, 0x00, 0x05, 0x00, 0x0b, 0x00, 0x06, 0x00, 0x28, 0x00, 0x08, 0x00, 0x21, 0x00, 0x09, 0x00, 0x20, 0x00, 0x0a, 0x00, 0x22, 0x00, 0x0b, 0x00, 0x25, 0x00, 0x0c, 0x00, 0x24, 0x00, 0x0d, 0x00, 0x23, 0x00, 0x0e, 0x00, 0x19, 0x00, 0x0f, 0x00, 0x16, 0x00, 0x10, 0x00, 0x15, 0x00, 0x11, 0x00, 0x1c, 0x00, 0x12, 0x00, 0x1b, 0x00, 0x13, 0x00, 0x1a, 0x00, 0x14, 0x00, 0x17, 0x00, 0x15, 0x00, 0x18, 0x00, 0x16, 0x00, 0x0e, 0x00, 0x18, 0x00, 0x0c, 0x00, 0x19, 0x00, 0x0d, 0x00, 0x1a, 0x00, 0x12, 0x00, 0x1b, 0x00, 0x14, 0x00, 0x1f, 0x00, 0x13, 0x00, 0x20, 0x00, 0x00, 0x00, 0x21, 0x00, 0x0a, 0x00, 0x22, 0x00, 0x06, 0x00, 0x23, 0x00, 0x07, 0x00, 0x24, 0x00, 0x08, 0x00, 0x25, 0x00, 0x09, 0x00, 0x26, 0x00, 0x04, 0x00, 0x27, 0x00, 0x03, 0x00, 0x28, 0x00, 0x02, 0x00, 0x29, 0x00, 0x01, 0x00, 0x2a, 0x00, 0x05, 0x00, 0x2b, 0x00, 0x2a, 0x00 }; /* some compilers need unsigned char to avoid warnings */ /* static tui8 g_unknown2[8] = { 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x04, 0x00 }; */ /*****************************************************************************/ static int APP_CC xrdp_rdp_read_config(struct xrdp_client_info* client_info) { int index = 0; struct list* items = (struct list *)NULL; struct list* values = (struct list *)NULL; char* item = (char *)NULL; char* value = (char *)NULL; char cfg_file[256]; /* initialize (zero out) local variables: */ g_memset(cfg_file,0,sizeof(char) * 256); items = list_create(); items->auto_free = 1; values = list_create(); values->auto_free = 1; g_snprintf(cfg_file, 255, "%s/xrdp.ini", XRDP_CFG_PATH); file_by_name_read_section(cfg_file, "globals", items, values); for (index = 0; index < items->count; index++) { item = (char*)list_get_item(items, index); value = (char*)list_get_item(values, index); if (g_strcasecmp(item, "bitmap_cache") == 0) { if ((g_strcasecmp(value, "yes") == 0) || (g_strcasecmp(value, "true") == 0) || (g_strcasecmp(value, "1") == 0)) { client_info->use_bitmap_cache = 1; } } else if (g_strcasecmp(item, "bitmap_compression") == 0) { if (g_strcasecmp(value, "yes") == 0 || g_strcasecmp(value, "true") == 0 || g_strcasecmp(value, "1") == 0) { client_info->use_bitmap_comp = 1; } } else if (g_strcasecmp(item, "crypt_level") == 0) { if (g_strcasecmp(value, "low") == 0) { client_info->crypt_level = 1; } else if (g_strcasecmp(value, "medium") == 0) { client_info->crypt_level = 2; } else if (g_strcasecmp(value, "high") == 0) { client_info->crypt_level = 3; } } else if (g_strcasecmp(item, "channel_code") == 0) { if (g_strcasecmp(value, "1") == 0) { client_info->channel_code = 1; } } else if (g_strcasecmp(item, "max_bpp") == 0) { client_info->max_bpp = g_atoi(value); } } list_delete(items); list_delete(values); return 0; } /*****************************************************************************/ struct xrdp_rdp* APP_CC xrdp_rdp_create(struct xrdp_session* session, struct trans* trans) { struct xrdp_rdp* self = (struct xrdp_rdp *)NULL; DEBUG(("in xrdp_rdp_create")); self = (struct xrdp_rdp*)g_malloc(sizeof(struct xrdp_rdp), 1); self->session = session; self->share_id = 66538; /* read ini settings */ xrdp_rdp_read_config(&self->client_info); /* create sec layer */ self->sec_layer = xrdp_sec_create(self, trans, self->client_info.crypt_level, self->client_info.channel_code); /* default 8 bit v1 color bitmap cache entries and size */ self->client_info.cache1_entries = 600; self->client_info.cache1_size = 256; self->client_info.cache2_entries = 300; self->client_info.cache2_size = 1024; self->client_info.cache3_entries = 262; self->client_info.cache3_size = 4096; g_write_ip_address(trans->sck, self->client_info.client_ip); /* load client ip info */ DEBUG(("out xrdp_rdp_create")); return self; } /*****************************************************************************/ void APP_CC xrdp_rdp_delete(struct xrdp_rdp* self) { if (self == 0) { return; } xrdp_sec_delete(self->sec_layer); g_free(self); } /*****************************************************************************/ int APP_CC xrdp_rdp_init(struct xrdp_rdp* self, struct stream* s) { if (xrdp_sec_init(self->sec_layer, s) != 0) { return 1; } s_push_layer(s, rdp_hdr, 6); return 0; } /*****************************************************************************/ int APP_CC xrdp_rdp_init_data(struct xrdp_rdp* self, struct stream* s) { if (xrdp_sec_init(self->sec_layer, s) != 0) { return 1; } s_push_layer(s, rdp_hdr, 18); return 0; } /*****************************************************************************/ /* returns erros */ int APP_CC xrdp_rdp_recv(struct xrdp_rdp* self, struct stream* s, int* code) { int error = 0; int len = 0; int pdu_code = 0; int chan = 0; DEBUG(("in xrdp_rdp_recv")); if (s->next_packet == 0 || s->next_packet >= s->end) { chan = 0; error = xrdp_sec_recv(self->sec_layer, s, &chan); if (error == -1) /* special code for send demand active */ { s->next_packet = 0; *code = -1; DEBUG(("out xrdp_rdp_recv")); return 0; } if (error != 0) { DEBUG(("out xrdp_rdp_recv error")); return 1; } if ((chan != MCS_GLOBAL_CHANNEL) && (chan > 0)) { if (chan > MCS_GLOBAL_CHANNEL) { xrdp_channel_process(self->sec_layer->chan_layer, s, chan); } s->next_packet = 0; *code = 0; DEBUG(("out xrdp_rdp_recv")); return 0; } s->next_packet = s->p; } else { s->p = s->next_packet; } if (!s_check_rem(s, 6)) { s->next_packet = 0; *code = 0; DEBUG(("out xrdp_rdp_recv")); len = (int)(s->end - s->p); g_writeln("xrdp_rdp_recv: bad RDP packet, length [%d]", len); return 0; } in_uint16_le(s, len); in_uint16_le(s, pdu_code); *code = pdu_code & 0xf; in_uint8s(s, 2); /* mcs user id */ s->next_packet += len; DEBUG(("out xrdp_rdp_recv")); return 0; } /*****************************************************************************/ int APP_CC xrdp_rdp_send(struct xrdp_rdp* self, struct stream* s, int pdu_type) { int len = 0; DEBUG(("in xrdp_rdp_send")); s_pop_layer(s, rdp_hdr); len = s->end - s->p; out_uint16_le(s, len); out_uint16_le(s, 0x10 | pdu_type); out_uint16_le(s, self->mcs_channel); if (xrdp_sec_send(self->sec_layer, s, MCS_GLOBAL_CHANNEL) != 0) { DEBUG(("out xrdp_rdp_send error")); return 1; } DEBUG(("out xrdp_rdp_send")); return 0; } /*****************************************************************************/ int APP_CC xrdp_rdp_send_data(struct xrdp_rdp* self, struct stream* s, int data_pdu_type) { int len = 0; DEBUG(("in xrdp_rdp_send_data")); s_pop_layer(s, rdp_hdr); len = s->end - s->p; out_uint16_le(s, len); out_uint16_le(s, 0x10 | RDP_PDU_DATA); out_uint16_le(s, self->mcs_channel); out_uint32_le(s, self->share_id); out_uint8(s, 0); out_uint8(s, 1); out_uint16_le(s, len - 14); out_uint8(s, data_pdu_type); out_uint8(s, 0); out_uint16_le(s, 0); if (xrdp_sec_send(self->sec_layer, s, MCS_GLOBAL_CHANNEL) != 0) { DEBUG(("out xrdp_rdp_send_data error")); return 1; } DEBUG(("out xrdp_rdp_send_data")); return 0; } /*****************************************************************************/ int APP_CC xrdp_rdp_send_data_update_sync(struct xrdp_rdp* self) { struct stream * s = (struct stream *)NULL; make_stream(s); init_stream(s, 8192); DEBUG(("in xrdp_rdp_send_data_update_sync")); if (xrdp_rdp_init_data(self, s) != 0) { DEBUG(("out xrdp_rdp_send_data_update_sync error")); free_stream(s); return 1; } out_uint16_le(s, RDP_UPDATE_SYNCHRONIZE); out_uint8s(s, 2); s_mark_end(s); if (xrdp_rdp_send_data(self, s, RDP_DATA_PDU_UPDATE) != 0) { DEBUG(("out xrdp_rdp_send_data_update_sync error")); free_stream(s); return 1; } DEBUG(("out xrdp_rdp_send_data_update_sync")); free_stream(s); return 0; } /*****************************************************************************/ static int APP_CC xrdp_rdp_parse_client_mcs_data(struct xrdp_rdp* self) { struct stream* p = (struct stream *)NULL; int i = 0; p = &(self->sec_layer->client_mcs_data); p->p = p->data; in_uint8s(p, 31); in_uint16_le(p, self->client_info.width); in_uint16_le(p, self->client_info.height); in_uint8s(p, 120); self->client_info.bpp = 8; in_uint16_le(p, i); switch (i) { case 0xca01: in_uint8s(p, 6); in_uint8(p, i); if (i > 8) { self->client_info.bpp = i; } break; case 0xca02: self->client_info.bpp = 15; break; case 0xca03: self->client_info.bpp = 16; break; case 0xca04: self->client_info.bpp = 24; break; } if (self->client_info.max_bpp > 0) { if (self->client_info.bpp > self->client_info.max_bpp) { self->client_info.bpp = self->client_info.max_bpp; } } p->p = p->data; DEBUG(("client width %d, client height %d bpp %d", self->client_info.width, self->client_info.height, self->client_info.bpp)); return 0; } /*****************************************************************************/ int APP_CC xrdp_rdp_incoming(struct xrdp_rdp* self) { DEBUG(("in xrdp_rdp_incoming")); if (xrdp_sec_incoming(self->sec_layer) != 0) { return 1; } self->mcs_channel = self->sec_layer->mcs_layer->userid + MCS_USERCHANNEL_BASE; xrdp_rdp_parse_client_mcs_data(self); DEBUG(("out xrdp_rdp_incoming mcs channel %d", self->mcs_channel)); return 0; } /*****************************************************************************/ int APP_CC xrdp_rdp_send_demand_active(struct xrdp_rdp* self) { struct stream* s; int caps_count; int caps_size; char* caps_count_ptr; char* caps_size_ptr; char* caps_ptr; make_stream(s); init_stream(s, 8192); if (xrdp_rdp_init(self, s) != 0) { free_stream(s); return 1; } caps_count = 0; out_uint32_le(s, self->share_id); out_uint16_le(s, 4); /* 4 chars for RDP\0 */ /* 2 bytes size after num caps, set later */ caps_size_ptr = s->p; out_uint8s(s, 2); out_uint8a(s, "RDP", 4); /* 4 byte num caps, set later */ caps_count_ptr = s->p; out_uint8s(s, 4); caps_ptr = s->p; /* Output share capability set */ caps_count++; out_uint16_le(s, RDP_CAPSET_SHARE); out_uint16_le(s, RDP_CAPLEN_SHARE); out_uint16_le(s, self->mcs_channel); out_uint16_be(s, 0xb5e2); /* 0x73e1 */ /* Output general capability set */ caps_count++; out_uint16_le(s, RDP_CAPSET_GENERAL); /* 1 */ out_uint16_le(s, RDP_CAPLEN_GENERAL); /* 24(0x18) */ out_uint16_le(s, 1); /* OS major type */ out_uint16_le(s, 3); /* OS minor type */ out_uint16_le(s, 0x200); /* Protocol version */ out_uint16_le(s, 0); /* pad */ out_uint16_le(s, 0); /* Compression types */ //out_uint16_le(s, 0); /* pad use 0x40d for rdp packets, 0 for not */ out_uint16_le(s, 0x40d); /* pad use 0x40d for rdp packets, 0 for not */ out_uint16_le(s, 0); /* Update capability */ out_uint16_le(s, 0); /* Remote unshare capability */ out_uint16_le(s, 0); /* Compression level */ out_uint16_le(s, 0); /* Pad */ /* Output bitmap capability set */ caps_count++; out_uint16_le(s, RDP_CAPSET_BITMAP); /* 2 */ out_uint16_le(s, RDP_CAPLEN_BITMAP); /* 28(0x1c) */ out_uint16_le(s, self->client_info.bpp); /* Preferred BPP */ out_uint16_le(s, 1); /* Receive 1 BPP */ out_uint16_le(s, 1); /* Receive 4 BPP */ out_uint16_le(s, 1); /* Receive 8 BPP */ out_uint16_le(s, self->client_info.width); /* width */ out_uint16_le(s, self->client_info.height); /* height */ out_uint16_le(s, 0); /* Pad */ out_uint16_le(s, 1); /* Allow resize */ out_uint16_le(s, 1); /* bitmap compression */ out_uint16_le(s, 0); /* unknown */ out_uint16_le(s, 0); /* unknown */ out_uint16_le(s, 0); /* pad */ /* Output font capability set */ caps_count++; out_uint16_le(s, RDP_CAPSET_FONT); /* 14 */ out_uint16_le(s, RDP_CAPLEN_FONT); /* 4 */ /* Output order capability set */ caps_count++; out_uint16_le(s, RDP_CAPSET_ORDER); /* 3 */ out_uint16_le(s, RDP_CAPLEN_ORDER); /* 88(0x58) */ out_uint8s(s, 16); out_uint32_be(s, 0x40420f00); out_uint16_le(s, 1); /* Cache X granularity */ out_uint16_le(s, 20); /* Cache Y granularity */ out_uint16_le(s, 0); /* Pad */ out_uint16_le(s, 1); /* Max order level */ out_uint16_le(s, 0x2f); /* Number of fonts */ out_uint16_le(s, 0x22); /* Capability flags */ /* caps */ out_uint8(s, 1); /* dest blt */ out_uint8(s, 1); /* pat blt */ out_uint8(s, 1); /* screen blt */ out_uint8(s, 1); /* mem blt */ out_uint8(s, 0); /* tri blt */ out_uint8(s, 0); /* unused */ out_uint8(s, 0); /* unused */ out_uint8(s, 0); /* nine grid */ out_uint8(s, 1); /* line to */ out_uint8(s, 0); /* multi nine grid */ out_uint8(s, 1); /* rect */ out_uint8(s, 0); /* desk save */ out_uint8(s, 0); /* unused */ out_uint8(s, 0); /* unused */ out_uint8(s, 0); /* unused */ out_uint8(s, 0); /* multi dest blt */ out_uint8(s, 0); /* multi pat blt */ out_uint8(s, 0); /* multi screen blt */ out_uint8(s, 1); /* multi rect */ out_uint8(s, 0); /* fast index */ out_uint8(s, 0); /* polygonSC ([MS-RDPEGDI], 2.2.2.2.1.1.2.16) */ out_uint8(s, 0); /* polygonCB ([MS-RDPEGDI], 2.2.2.2.1.1.2.17) */ out_uint8(s, 0); /* polyline */ out_uint8(s, 0); /* unused */ out_uint8(s, 0); /* fast glyph */ out_uint8(s, 0); /* ellipse */ out_uint8(s, 0); /* ellipse */ out_uint8(s, 0); /* ? */ out_uint8(s, 0); /* unused */ out_uint8(s, 0); /* unused */ out_uint8(s, 0); /* unused */ out_uint8(s, 0); /* unused */ out_uint16_le(s, 0x6a1); out_uint8s(s, 2); /* ? */ out_uint32_le(s, 0x0f4240); /* desk save */ out_uint32_le(s, 0x0f4240); /* desk save */ out_uint32_le(s, 1); /* ? */ out_uint32_le(s, 0); /* ? */ /* Output color cache capability set */ caps_count++; out_uint16_le(s, RDP_CAPSET_COLCACHE); out_uint16_le(s, RDP_CAPLEN_COLCACHE); out_uint16_le(s, 6); /* cache size */ out_uint16_le(s, 0); /* pad */ /* Output pointer capability set */ caps_count++; out_uint16_le(s, RDP_CAPSET_POINTER); out_uint16_le(s, RDP_CAPLEN_POINTER); out_uint16_le(s, 1); /* Colour pointer */ out_uint16_le(s, 0x19); /* Cache size */ out_uint16_le(s, 0x19); /* Cache size */ /* Output input capability set */ caps_count++; out_uint16_le(s, RDP_CAPSET_INPUT); /* 13(0xd) */ out_uint16_le(s, RDP_CAPLEN_INPUT); /* 88(0x58) */ out_uint8(s, 1); out_uint8s(s, 83); out_uint8s(s, 4); /* pad */ s_mark_end(s); caps_size = (int)(s->end - caps_ptr); caps_size_ptr[0] = caps_size; caps_size_ptr[1] = caps_size >> 8; caps_count_ptr[0] = caps_count; caps_count_ptr[1] = caps_count >> 8; caps_count_ptr[2] = caps_count >> 16; caps_count_ptr[3] = caps_count >> 24; if (xrdp_rdp_send(self, s, RDP_PDU_DEMAND_ACTIVE) != 0) { free_stream(s); return 1; } free_stream(s); return 0; } /*****************************************************************************/ static int APP_CC xrdp_process_capset_general(struct xrdp_rdp* self, struct stream* s, int len) { int i; in_uint8s(s, 10); in_uint16_le(s, i); /* use_compact_packets is pretty much 'use rdp5' */ self->client_info.use_compact_packets = (i != 0); /* op2 is a boolean to use compact bitmap headers in bitmap cache */ /* set it to same as 'use rdp5' boolean */ self->client_info.op2 = self->client_info.use_compact_packets; return 0; } /*****************************************************************************/ static int APP_CC xrdp_process_capset_order(struct xrdp_rdp* self, struct stream* s, int len) { int i; char order_caps[32]; DEBUG(("order capabilities")); in_uint8s(s, 20); /* Terminal desc, pad */ in_uint8s(s, 2); /* Cache X granularity */ in_uint8s(s, 2); /* Cache Y granularity */ in_uint8s(s, 2); /* Pad */ in_uint8s(s, 2); /* Max order level */ in_uint8s(s, 2); /* Number of fonts */ in_uint8s(s, 2); /* Capability flags */ in_uint8a(s, order_caps, 32); /* Orders supported */ DEBUG(("dest blt-0 %d", order_caps[0])); DEBUG(("pat blt-1 %d", order_caps[1])); DEBUG(("screen blt-2 %d", order_caps[2])); DEBUG(("memblt-3-13 %d %d", order_caps[3], order_caps[13])); DEBUG(("triblt-4-14 %d %d", order_caps[4], order_caps[14])); DEBUG(("line-8 %d", order_caps[8])); DEBUG(("line-9 %d", order_caps[9])); DEBUG(("rect-10 %d", order_caps[10])); DEBUG(("desksave-11 %d", order_caps[11])); DEBUG(("polygon-20 %d", order_caps[20])); DEBUG(("polygon2-21 %d", order_caps[21])); DEBUG(("polyline-22 %d", order_caps[22])); DEBUG(("ellipse-25 %d", order_caps[25])); DEBUG(("ellipse2-26 %d", order_caps[26])); DEBUG(("text2-27 %d", order_caps[27])); DEBUG(("order_caps dump")); #if defined(XRDP_DEBUG) g_hexdump(order_caps, 32); #endif in_uint8s(s, 2); /* Text capability flags */ in_uint8s(s, 6); /* Pad */ in_uint32_le(s, i); /* desktop cache size, usually 0x38400 */ self->client_info.desktop_cache = i; DEBUG(("desktop cache size %d", i)); in_uint8s(s, 4); /* Unknown */ in_uint8s(s, 4); /* Unknown */ return 0; } /*****************************************************************************/ /* get the bitmap cache size */ static int APP_CC xrdp_process_capset_bmpcache(struct xrdp_rdp* self, struct stream* s, int len) { in_uint8s(s, 24); in_uint16_le(s, self->client_info.cache1_entries); in_uint16_le(s, self->client_info.cache1_size); in_uint16_le(s, self->client_info.cache2_entries); in_uint16_le(s, self->client_info.cache2_size); in_uint16_le(s, self->client_info.cache3_entries); in_uint16_le(s, self->client_info.cache3_size); DEBUG(("cache1 entries %d size %d", self->client_info.cache1_entries, self->client_info.cache1_size)); DEBUG(("cache2 entries %d size %d", self->client_info.cache2_entries, self->client_info.cache2_size)); DEBUG(("cache3 entries %d size %d", self->client_info.cache3_entries, self->client_info.cache3_size)); return 0; } /*****************************************************************************/ /* get the bitmap cache size */ static int APP_CC xrdp_process_capset_bmpcache2(struct xrdp_rdp* self, struct stream* s, int len) { int Bpp = 0; int i = 0; self->client_info.bitmap_cache_version = 2; Bpp = (self->client_info.bpp + 7) / 8; in_uint16_le(s, i); self->client_info.bitmap_cache_persist_enable = i; in_uint8s(s, 2); /* number of caches in set, 3 */ in_uint32_le(s, i); i = MIN(i, 2000); self->client_info.cache1_entries = i; self->client_info.cache1_size = 256 * Bpp; in_uint32_le(s, i); i = MIN(i, 2000); self->client_info.cache2_entries = i; self->client_info.cache2_size = 1024 * Bpp; in_uint32_le(s, i); i = i & 0x7fffffff; i = MIN(i, 2000); self->client_info.cache3_entries = i; self->client_info.cache3_size = 4096 * Bpp; DEBUG(("cache1 entries %d size %d", self->client_info.cache1_entries, self->client_info.cache1_size)); DEBUG(("cache2 entries %d size %d", self->client_info.cache2_entries, self->client_info.cache2_size)); DEBUG(("cache3 entries %d size %d", self->client_info.cache3_entries, self->client_info.cache3_size)); return 0; } /*****************************************************************************/ /* get the number of client cursor cache */ static int APP_CC xrdp_process_capset_pointercache(struct xrdp_rdp* self, struct stream* s, int len) { int i; in_uint8s(s, 2); /* color pointer */ in_uint16_le(s, i); i = MIN(i, 32); self->client_info.pointer_cache_entries = i; return 0; } /*****************************************************************************/ /* get the type of client brush cache */ static int APP_CC xrdp_process_capset_brushcache(struct xrdp_rdp* self, struct stream* s, int len) { int code; in_uint32_le(s, code); self->client_info.brush_cache_code = code; return 0; } /*****************************************************************************/ int APP_CC xrdp_rdp_process_confirm_active(struct xrdp_rdp* self, struct stream* s) { int cap_len; int source_len; int num_caps; int index; int type; int len; char* p; DEBUG(("in xrdp_rdp_process_confirm_active")); in_uint8s(s, 4); /* rdp_shareid */ in_uint8s(s, 2); /* userid */ in_uint16_le(s, source_len); /* sizeof RDP_SOURCE */ in_uint16_le(s, cap_len); in_uint8s(s, source_len); in_uint16_le(s, num_caps); in_uint8s(s, 2); /* pad */ for (index = 0; index < num_caps; index++) { p = s->p; in_uint16_le(s, type); in_uint16_le(s, len); switch (type) { case RDP_CAPSET_GENERAL: /* 1 */ DEBUG(("RDP_CAPSET_GENERAL")); xrdp_process_capset_general(self, s, len); break; case RDP_CAPSET_BITMAP: /* 2 */ DEBUG(("RDP_CAPSET_BITMAP")); break; case RDP_CAPSET_ORDER: /* 3 */ DEBUG(("RDP_CAPSET_ORDER")); xrdp_process_capset_order(self, s, len); break; case RDP_CAPSET_BMPCACHE: /* 4 */ DEBUG(("RDP_CAPSET_BMPCACHE")); xrdp_process_capset_bmpcache(self, s, len); break; case RDP_CAPSET_CONTROL: /* 5 */ DEBUG(("RDP_CAPSET_CONTROL")); break; case RDP_CAPSET_ACTIVATE: /* 7 */ DEBUG(("RDP_CAPSET_ACTIVATE")); break; case RDP_CAPSET_POINTER: /* 8 */ DEBUG(("RDP_CAPSET_POINTER")); xrdp_process_capset_pointercache(self, s, len); break; case RDP_CAPSET_SHARE: /* 9 */ DEBUG(("RDP_CAPSET_SHARE")); break; case RDP_CAPSET_COLCACHE: /* 10 */ DEBUG(("RDP_CAPSET_COLCACHE")); break; case 12: /* 12 */ DEBUG(("--12")); break; case 13: /* 13 */ DEBUG(("--13")); break; case 14: /* 14 */ DEBUG(("--14")); break; case RDP_CAPSET_BRUSHCACHE: /* 15 */ xrdp_process_capset_brushcache(self, s, len); break; case 16: /* 16 */ DEBUG(("--16")); break; case 17: /* 17 */ DEBUG(("--16")); break; case RDP_CAPSET_BMPCACHE2: /* 19 */ DEBUG(("RDP_CAPSET_BMPCACHE2")); xrdp_process_capset_bmpcache2(self, s, len); break; case 20: /* 20 */ DEBUG(("--20")); break; case 21: /* 21 */ DEBUG(("--21")); break; case 22: /* 22 */ DEBUG(("--22")); break; case 26: /* 26 */ DEBUG(("--26")); break; default: g_writeln("unknown in xrdp_rdp_process_confirm_active %d", type); break; } s->p = p + len; } DEBUG(("out xrdp_rdp_process_confirm_active")); return 0; } /*****************************************************************************/ static int APP_CC xrdp_rdp_process_data_pointer(struct xrdp_rdp* self, struct stream* s) { return 0; } /*****************************************************************************/ /* RDP_DATA_PDU_INPUT */ static int APP_CC xrdp_rdp_process_data_input(struct xrdp_rdp* self, struct stream* s) { int num_events; int index; int msg_type; int device_flags; int param1; int param2; int time; in_uint16_le(s, num_events); in_uint8s(s, 2); /* pad */ DEBUG(("in xrdp_rdp_process_data_input %d events", num_events)); for (index = 0; index < num_events; index++) { in_uint32_le(s, time); in_uint16_le(s, msg_type); in_uint16_le(s, device_flags); in_sint16_le(s, param1); in_sint16_le(s, param2); DEBUG(("xrdp_rdp_process_data_input event %4.4x flags %4.4x param1 %d \ param2 %d time %d", msg_type, device_flags, param1, param2, time)); if (self->session->callback != 0) { /* msg_type can be RDP_INPUT_SYNCHRONIZE - 0 RDP_INPUT_SCANCODE - 4 RDP_INPUT_MOUSE - 0x8001 */ /* call to xrdp_wm.c : callback */ self->session->callback(self->session->id, msg_type, param1, param2, device_flags, time); } } DEBUG(("out xrdp_rdp_process_data_input")); return 0; } /*****************************************************************************/ static int APP_CC xrdp_rdp_send_synchronise(struct xrdp_rdp* self) { struct stream* s; make_stream(s); init_stream(s, 8192); if (xrdp_rdp_init_data(self, s) != 0) { free_stream(s); return 1; } out_uint16_le(s, 1); out_uint16_le(s, 1002); s_mark_end(s); if (xrdp_rdp_send_data(self, s, RDP_DATA_PDU_SYNCHRONISE) != 0) { free_stream(s); return 1; } free_stream(s); return 0; } /*****************************************************************************/ static int APP_CC xrdp_rdp_send_control(struct xrdp_rdp* self, int action) { struct stream* s; make_stream(s); init_stream(s, 8192); if (xrdp_rdp_init_data(self, s) != 0) { free_stream(s); return 1; } out_uint16_le(s, action); out_uint16_le(s, 0); /* userid */ out_uint32_le(s, 1002); /* control id */ s_mark_end(s); if (xrdp_rdp_send_data(self, s, RDP_DATA_PDU_CONTROL) != 0) { free_stream(s); return 1; } free_stream(s); return 0; } /*****************************************************************************/ static int APP_CC xrdp_rdp_process_data_control(struct xrdp_rdp* self, struct stream* s) { int action; DEBUG(("xrdp_rdp_process_data_control")); in_uint16_le(s, action); in_uint8s(s, 2); /* user id */ in_uint8s(s, 4); /* control id */ if (action == RDP_CTL_REQUEST_CONTROL) { DEBUG(("xrdp_rdp_process_data_control got RDP_CTL_REQUEST_CONTROL")); DEBUG(("xrdp_rdp_process_data_control calling xrdp_rdp_send_synchronise")); xrdp_rdp_send_synchronise(self); DEBUG(("xrdp_rdp_process_data_control sending RDP_CTL_COOPERATE")); xrdp_rdp_send_control(self, RDP_CTL_COOPERATE); DEBUG(("xrdp_rdp_process_data_control sending RDP_CTL_GRANT_CONTROL")); xrdp_rdp_send_control(self, RDP_CTL_GRANT_CONTROL); } else { DEBUG(("xrdp_rdp_process_data_control unknown action")); } return 0; } /*****************************************************************************/ static int APP_CC xrdp_rdp_process_data_sync(struct xrdp_rdp* self) { DEBUG(("xrdp_rdp_process_data_sync")); return 0; } /*****************************************************************************/ static int APP_CC xrdp_rdp_process_screen_update(struct xrdp_rdp* self, struct stream* s) { int op; int left; int top; int right; int bottom; int cx; int cy; in_uint32_le(s, op); in_uint16_le(s, left); in_uint16_le(s, top); in_uint16_le(s, right); in_uint16_le(s, bottom); cx = (right - left) + 1; cy = (bottom - top) + 1; if (self->session->callback != 0) { self->session->callback(self->session->id, 0x4444, left, top, cx, cy); } return 0; } /*****************************************************************************/ static int APP_CC xrdp_rdp_send_unknown1(struct xrdp_rdp* self) { struct stream* s; make_stream(s); init_stream(s, 8192); if (xrdp_rdp_init_data(self, s) != 0) { free_stream(s); return 1; } out_uint8a(s, g_unknown1, 172); s_mark_end(s); if (xrdp_rdp_send_data(self, s, 0x28) != 0) { free_stream(s); return 1; } free_stream(s); return 0; } /*****************************************************************************/ static int APP_CC xrdp_rdp_process_data_font(struct xrdp_rdp* self, struct stream* s) { int seq; DEBUG(("in xrdp_rdp_process_data_font")); in_uint8s(s, 2); /* num of fonts */ in_uint8s(s, 2); /* unknown */ in_uint16_le(s, seq); /* 419 client sends Seq 1, then 2 */ /* 2600 clients sends only Seq 3 */ if (seq == 2 || seq == 3) /* after second font message, we are up and */ { /* running */ DEBUG(("sending unknown1")); xrdp_rdp_send_unknown1(self); self->session->up_and_running = 1; DEBUG(("up_and_running set")); xrdp_rdp_send_data_update_sync(self); } DEBUG(("out xrdp_rdp_process_data_font")); return 0; } /*****************************************************************************/ /* sent 37 pdu */ static int APP_CC xrdp_rdp_send_disconnect_query_response(struct xrdp_rdp* self) { struct stream* s; make_stream(s); init_stream(s, 8192); if (xrdp_rdp_init_data(self, s) != 0) { free_stream(s); return 1; } s_mark_end(s); if (xrdp_rdp_send_data(self, s, 37) != 0) { free_stream(s); return 1; } free_stream(s); return 0; } #if 0 /* not used */ /*****************************************************************************/ /* sent RDP_DATA_PDU_DISCONNECT 47 pdu */ static int APP_CC xrdp_rdp_send_disconnect_reason(struct xrdp_rdp* self, int reason) { struct stream* s; make_stream(s); init_stream(s, 8192); if (xrdp_rdp_init_data(self, s) != 0) { free_stream(s); return 1; } out_uint32_le(s, reason); s_mark_end(s); if (xrdp_rdp_send_data(self, s, RDP_DATA_PDU_DISCONNECT) != 0) { free_stream(s); return 1; } free_stream(s); return 0; } #endif /*****************************************************************************/ /* RDP_PDU_DATA */ int APP_CC xrdp_rdp_process_data(struct xrdp_rdp* self, struct stream* s) { int len; int data_type; int ctype; int clen; in_uint8s(s, 6); in_uint16_le(s, len); in_uint8(s, data_type); in_uint8(s, ctype); in_uint16_le(s, clen); DEBUG(("xrdp_rdp_process_data code %d", data_type)); switch (data_type) { case RDP_DATA_PDU_POINTER: /* 27(0x1b) */ xrdp_rdp_process_data_pointer(self, s); break; case RDP_DATA_PDU_INPUT: /* 28(0x1c) */ xrdp_rdp_process_data_input(self, s); break; case RDP_DATA_PDU_CONTROL: /* 20(0x14) */ xrdp_rdp_process_data_control(self, s); break; case RDP_DATA_PDU_SYNCHRONISE: /* 31(0x1f) */ xrdp_rdp_process_data_sync(self); break; case 33: /* 33(0x21) ?? Invalidate an area I think */ xrdp_rdp_process_screen_update(self, s); break; case 35: /* 35(0x23) */ /* 35 ?? this comes when minimuzing a full screen mstsc.exe 2600 */ /* I think this is saying the client no longer wants screen */ /* updates and it will issue a 33 above to catch up */ /* so minimized apps don't take bandwidth */ break; case 36: /* 36(0x24) ?? disconnect query? */ /* when this message comes, send a 37 back so the client */ /* is sure the connection is alive and it can ask if user */ /* really wants to disconnect */ xrdp_rdp_send_disconnect_query_response(self); /* send a 37 back */ break; case RDP_DATA_PDU_FONT2: /* 39(0x27) */ xrdp_rdp_process_data_font(self, s); break; default: g_writeln("unknown in xrdp_rdp_process_data %d", data_type); break; } return 0; } /*****************************************************************************/ int APP_CC xrdp_rdp_disconnect(struct xrdp_rdp* self) { int rv; DEBUG(("in xrdp_rdp_disconnect")); rv = xrdp_sec_disconnect(self->sec_layer); DEBUG(("out xrdp_rdp_disconnect")); return rv; } /*****************************************************************************/ int APP_CC xrdp_rdp_send_deactive(struct xrdp_rdp* self) { struct stream* s; DEBUG(("in xrdp_rdp_send_deactive")); make_stream(s); init_stream(s, 8192); if (xrdp_rdp_init(self, s) != 0) { free_stream(s); DEBUG(("out xrdp_rdp_send_deactive error")); return 1; } s_mark_end(s); if (xrdp_rdp_send(self, s, RDP_PDU_DEACTIVATE) != 0) { free_stream(s); DEBUG(("out xrdp_rdp_send_deactive error")); return 1; } free_stream(s); DEBUG(("out xrdp_rdp_send_deactive")); return 0; } xrdp-0.6.0/libxrdp/xrdp_sec.c000066400000000000000000000720131203155130500161070ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2004-2010 secure layer */ #include "libxrdp.h" /* some compilers need unsigned char to avoid warnings */ static tui8 g_pad_54[40] = { 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54 }; /* some compilers need unsigned char to avoid warnings */ static tui8 g_pad_92[48] = { 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92 }; /* some compilers need unsigned char to avoid warnings */ static tui8 g_lic1[322] = { 0x80, 0x00, 0x3e, 0x01, 0x01, 0x02, 0x3e, 0x01, 0x7b, 0x3c, 0x31, 0xa6, 0xae, 0xe8, 0x74, 0xf6, 0xb4, 0xa5, 0x03, 0x90, 0xe7, 0xc2, 0xc7, 0x39, 0xba, 0x53, 0x1c, 0x30, 0x54, 0x6e, 0x90, 0x05, 0xd0, 0x05, 0xce, 0x44, 0x18, 0x91, 0x83, 0x81, 0x00, 0x00, 0x04, 0x00, 0x2c, 0x00, 0x00, 0x00, 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, 0x08, 0x00, 0x00, 0x00, 0x32, 0x00, 0x33, 0x00, 0x36, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0xb8, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x06, 0x00, 0x5c, 0x00, 0x52, 0x53, 0x41, 0x31, 0x48, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0xc7, 0xc9, 0xf7, 0x8e, 0x5a, 0x38, 0xe4, 0x29, 0xc3, 0x00, 0x95, 0x2d, 0xdd, 0x4c, 0x3e, 0x50, 0x45, 0x0b, 0x0d, 0x9e, 0x2a, 0x5d, 0x18, 0x63, 0x64, 0xc4, 0x2c, 0xf7, 0x8f, 0x29, 0xd5, 0x3f, 0xc5, 0x35, 0x22, 0x34, 0xff, 0xad, 0x3a, 0xe6, 0xe3, 0x95, 0x06, 0xae, 0x55, 0x82, 0xe3, 0xc8, 0xc7, 0xb4, 0xa8, 0x47, 0xc8, 0x50, 0x71, 0x74, 0x29, 0x53, 0x89, 0x6d, 0x9c, 0xed, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x48, 0x00, 0xa8, 0xf4, 0x31, 0xb9, 0xab, 0x4b, 0xe6, 0xb4, 0xf4, 0x39, 0x89, 0xd6, 0xb1, 0xda, 0xf6, 0x1e, 0xec, 0xb1, 0xf0, 0x54, 0x3b, 0x5e, 0x3e, 0x6a, 0x71, 0xb4, 0xf7, 0x75, 0xc8, 0x16, 0x2f, 0x24, 0x00, 0xde, 0xe9, 0x82, 0x99, 0x5f, 0x33, 0x0b, 0xa9, 0xa6, 0x94, 0xaf, 0xcb, 0x11, 0xc3, 0xf2, 0xdb, 0x09, 0x42, 0x68, 0x29, 0x56, 0x58, 0x01, 0x56, 0xdb, 0x59, 0x03, 0x69, 0xdb, 0x7d, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x0e, 0x00, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x00 }; /* some compilers need unsigned char to avoid warnings */ static tui8 g_lic2[20] = { 0x80, 0x00, 0x10, 0x00, 0xff, 0x02, 0x10, 0x00, 0x07, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x28, 0x14, 0x00, 0x00 }; /* mce */ /* some compilers need unsigned char to avoid warnings */ static tui8 g_lic3[20] = { 0x80, 0x02, 0x10, 0x00, 0xff, 0x03, 0x10, 0x00, 0x07, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xf3, 0x99, 0x00, 0x00 }; /*****************************************************************************/ static void APP_CC hex_str_to_bin(char* in, char* out, int out_len) { int in_index; int in_len; int out_index; int val; char hex[16]; in_len = g_strlen(in); out_index = 0; in_index = 0; while (in_index <= (in_len - 4)) { if ((in[in_index] == '0') && (in[in_index + 1] == 'x')) { hex[0] = in[in_index + 2]; hex[1] = in[in_index + 3]; hex[2] = 0; if (out_index < out_len) { val = g_htoi(hex); out[out_index] = val; } out_index++; } in_index++; } } /*****************************************************************************/ struct xrdp_sec* APP_CC xrdp_sec_create(struct xrdp_rdp* owner, struct trans* trans, int crypt_level, int channel_code) { struct xrdp_sec* self; DEBUG((" in xrdp_sec_create")); self = (struct xrdp_sec*)g_malloc(sizeof(struct xrdp_sec), 1); self->rdp_layer = owner; self->rc4_key_size = 1; /* 1 = 40 bit, 2 = 128 bit */ self->crypt_level = 1; /* 1, 2, 3 = low, medium, high */ switch (crypt_level) { case 1: self->rc4_key_size = 1; self->crypt_level = 1; break; case 2: self->rc4_key_size = 1; self->crypt_level = 2; break; case 3: self->rc4_key_size = 2; self->crypt_level = 3; break; } self->channel_code = channel_code; self->decrypt_rc4_info = ssl_rc4_info_create(); self->encrypt_rc4_info = ssl_rc4_info_create(); self->mcs_layer = xrdp_mcs_create(self, trans, &self->client_mcs_data, &self->server_mcs_data); self->chan_layer = xrdp_channel_create(self, self->mcs_layer); DEBUG((" out xrdp_sec_create")); return self; } /*****************************************************************************/ void APP_CC xrdp_sec_delete(struct xrdp_sec* self) { if (self == 0) { return; } xrdp_channel_delete(self->chan_layer); xrdp_mcs_delete(self->mcs_layer); ssl_rc4_info_delete(self->decrypt_rc4_info); ssl_rc4_info_delete(self->encrypt_rc4_info); g_free(self->client_mcs_data.data); g_free(self->server_mcs_data.data); g_free(self); } /*****************************************************************************/ /* returns error */ int APP_CC xrdp_sec_init(struct xrdp_sec* self, struct stream* s) { if (xrdp_mcs_init(self->mcs_layer, s) != 0) { return 1; } if (self->crypt_level > 1) { s_push_layer(s, sec_hdr, 4 + 8); } else { s_push_layer(s, sec_hdr, 4); } return 0; } /*****************************************************************************/ /* Reduce key entropy from 64 to 40 bits */ static void APP_CC xrdp_sec_make_40bit(char* key) { key[0] = 0xd1; key[1] = 0x26; key[2] = 0x9e; } /*****************************************************************************/ /* returns error */ /* update an encryption key */ static int APP_CC xrdp_sec_update(char* key, char* update_key, int key_len) { char shasig[20]; void* sha1_info; void* md5_info; void* rc4_info; sha1_info = ssl_sha1_info_create(); md5_info = ssl_md5_info_create(); rc4_info = ssl_rc4_info_create(); ssl_sha1_clear(sha1_info); ssl_sha1_transform(sha1_info, update_key, key_len); ssl_sha1_transform(sha1_info, (char*)g_pad_54, 40); ssl_sha1_transform(sha1_info, key, key_len); ssl_sha1_complete(sha1_info, shasig); ssl_md5_clear(md5_info); ssl_md5_transform(md5_info, update_key, key_len); ssl_md5_transform(md5_info, (char*)g_pad_92, 48); ssl_md5_transform(md5_info, shasig, 20); ssl_md5_complete(md5_info, key); ssl_rc4_set_key(rc4_info, key, key_len); ssl_rc4_crypt(rc4_info, key, key_len); if (key_len == 8) { xrdp_sec_make_40bit(key); } ssl_sha1_info_delete(sha1_info); ssl_md5_info_delete(md5_info); ssl_rc4_info_delete(rc4_info); return 0; } /*****************************************************************************/ static void APP_CC xrdp_sec_decrypt(struct xrdp_sec* self, char* data, int len) { if (self->decrypt_use_count == 4096) { xrdp_sec_update(self->decrypt_key, self->decrypt_update_key, self->rc4_key_len); ssl_rc4_set_key(self->decrypt_rc4_info, self->decrypt_key, self->rc4_key_len); self->decrypt_use_count = 0; } ssl_rc4_crypt(self->decrypt_rc4_info, data, len); self->decrypt_use_count++; } /*****************************************************************************/ static void APP_CC xrdp_sec_encrypt(struct xrdp_sec* self, char* data, int len) { if (self->encrypt_use_count == 4096) { xrdp_sec_update(self->encrypt_key, self->encrypt_update_key, self->rc4_key_len); ssl_rc4_set_key(self->encrypt_rc4_info, self->encrypt_key, self->rc4_key_len); self->encrypt_use_count = 0; } ssl_rc4_crypt(self->encrypt_rc4_info, data, len); self->encrypt_use_count++; } /*****************************************************************************/ static int APP_CC unicode_in(struct stream* s, int uni_len, char* dst, int dst_len) { int dst_index; int src_index; dst_index = 0; src_index = 0; while (src_index < uni_len) { if (dst_index >= dst_len || src_index > 512) { break; } in_uint8(s, dst[dst_index]); in_uint8s(s, 1); dst_index++; src_index += 2; } in_uint8s(s, 2); return 0; } /*****************************************************************************/ /* returns error */ static int APP_CC xrdp_sec_process_logon_info(struct xrdp_sec* self, struct stream* s) { int flags = 0; int len_domain = 0; int len_user = 0; int len_password = 0; int len_program = 0; int len_directory = 0; int len_ip = 0; int len_dll = 0; int tzone = 0; char tmpdata[256]; /* initialize (zero out) local variables */ g_memset(tmpdata,0,sizeof(char)*256); in_uint8s(s, 4); in_uint32_le(s, flags); DEBUG(("in xrdp_sec_process_logon_info flags $%x", flags)); /* this is the first test that the decrypt is working */ if ((flags & RDP_LOGON_NORMAL) != RDP_LOGON_NORMAL) /* 0x33 */ { /* must be or error */ DEBUG(("xrdp_sec_process_logon_info: flags wrong, major error")); return 1; } if (flags & RDP_LOGON_LEAVE_AUDIO) { self->rdp_layer->client_info.sound_code = 1; DEBUG(("flag RDP_LOGON_LEAVE_AUDIO found")); } if ((flags & RDP_LOGON_AUTO) && (!self->rdp_layer->client_info.is_mce)) /* todo, for now not allowing autologon and mce both */ { self->rdp_layer->client_info.rdp_autologin = 1; DEBUG(("flag RDP_LOGON_AUTO found")); } if (flags & RDP_COMPRESSION) { self->rdp_layer->client_info.rdp_compression = 1; DEBUG(("flag RDP_COMPRESSION found")); } in_uint16_le(s, len_domain); if (len_domain > 511) { DEBUG(("ERROR [xrdp_sec_process_logon_info()]: len_domain > 511")); return 1; } in_uint16_le(s, len_user); if (len_user > 511) { DEBUG(("ERROR [xrdp_sec_process_logon_info()]: len_user > 511")); return 1; } in_uint16_le(s, len_password); if (len_password > 511) { DEBUG(("ERROR [xrdp_sec_process_logon_info()]: len_password > 511")); return 1; } in_uint16_le(s, len_program); if (len_program > 511) { DEBUG(("ERROR [xrdp_sec_process_logon_info()]: len_program > 511")); return 1; } in_uint16_le(s, len_directory); if (len_directory > 511) { DEBUG(("ERROR [xrdp_sec_process_logon_info()]: len_directory > 511")); return 1; } unicode_in(s, len_domain, self->rdp_layer->client_info.domain, 255); DEBUG(("domain %s", self->rdp_layer->client_info.domain)); unicode_in(s, len_user, self->rdp_layer->client_info.username, 255); DEBUG(("username %s", self->rdp_layer->client_info.username)); if (flags & RDP_LOGON_AUTO) { unicode_in(s, len_password, self->rdp_layer->client_info.password, 255); DEBUG(("flag RDP_LOGON_AUTO found")); } else { in_uint8s(s, len_password + 2); } unicode_in(s, len_program, self->rdp_layer->client_info.program, 255); DEBUG(("program %s", self->rdp_layer->client_info.program)); unicode_in(s, len_directory, self->rdp_layer->client_info.directory, 255); DEBUG(("directory %s", self->rdp_layer->client_info.directory)); if (flags & RDP_LOGON_BLOB) { in_uint8s(s, 2); /* unknown */ in_uint16_le(s, len_ip); unicode_in(s, len_ip - 2, tmpdata, 255); in_uint16_le(s, len_dll); unicode_in(s, len_dll - 2, tmpdata, 255); in_uint32_le(s, tzone); /* len of timetone */ in_uint8s(s, 62); /* skip */ in_uint8s(s, 22); /* skip misc. */ in_uint8s(s, 62); /* skip */ in_uint8s(s, 26); /* skip stuff */ in_uint32_le(s, self->rdp_layer->client_info.rdp5_performanceflags); } DEBUG(("out xrdp_sec_process_logon_info")); return 0; } /*****************************************************************************/ /* returns error */ static int APP_CC xrdp_sec_send_lic_initial(struct xrdp_sec* self) { struct stream* s = (struct stream *)NULL; make_stream(s); init_stream(s, 8192); if (xrdp_mcs_init(self->mcs_layer, s) != 0) { free_stream(s); return 1; } out_uint8a(s, g_lic1, 322); s_mark_end(s); if (xrdp_mcs_send(self->mcs_layer, s, MCS_GLOBAL_CHANNEL) != 0) { free_stream(s); return 1; } free_stream(s); return 0; } /*****************************************************************************/ /* returns error */ static int APP_CC xrdp_sec_send_lic_response(struct xrdp_sec* self) { struct stream* s; make_stream(s); init_stream(s, 8192); if (xrdp_mcs_init(self->mcs_layer, s) != 0) { free_stream(s); return 1; } out_uint8a(s, g_lic2, 20); s_mark_end(s); if (xrdp_mcs_send(self->mcs_layer, s, MCS_GLOBAL_CHANNEL) != 0) { free_stream(s); return 1; } free_stream(s); return 0; } /*****************************************************************************/ /* returns error */ static int APP_CC xrdp_sec_send_media_lic_response(struct xrdp_sec* self) { struct stream* s; make_stream(s); init_stream(s, 8192); if (xrdp_mcs_init(self->mcs_layer, s) != 0) { free_stream(s); return 1; } out_uint8a(s, g_lic3, sizeof(g_lic3)); s_mark_end(s); if (xrdp_mcs_send(self->mcs_layer, s, MCS_GLOBAL_CHANNEL) != 0) { free_stream(s); return 1; } free_stream(s); return 0; } /*****************************************************************************/ static void APP_CC xrdp_sec_rsa_op(char* out, char* in, char* mod, char* exp) { ssl_mod_exp(out, 64, in, 64, mod, 64, exp, 64); } /*****************************************************************************/ static void APP_CC xrdp_sec_hash_48(char* out, char* in, char* salt1, char* salt2, int salt) { int i; void* sha1_info; void* md5_info; char pad[4]; char sha1_sig[20]; char md5_sig[16]; sha1_info = ssl_sha1_info_create(); md5_info = ssl_md5_info_create(); for (i = 0; i < 3; i++) { g_memset(pad, salt + i, 4); ssl_sha1_clear(sha1_info); ssl_sha1_transform(sha1_info, pad, i + 1); ssl_sha1_transform(sha1_info, in, 48); ssl_sha1_transform(sha1_info, salt1, 32); ssl_sha1_transform(sha1_info, salt2, 32); ssl_sha1_complete(sha1_info, sha1_sig); ssl_md5_clear(md5_info); ssl_md5_transform(md5_info, in, 48); ssl_md5_transform(md5_info, sha1_sig, 20); ssl_md5_complete(md5_info, md5_sig); g_memcpy(out + i * 16, md5_sig, 16); } ssl_sha1_info_delete(sha1_info); ssl_md5_info_delete(md5_info); } /*****************************************************************************/ static void APP_CC xrdp_sec_hash_16(char* out, char* in, char* salt1, char* salt2) { void* md5_info; md5_info = ssl_md5_info_create(); ssl_md5_clear(md5_info); ssl_md5_transform(md5_info, in, 16); ssl_md5_transform(md5_info, salt1, 32); ssl_md5_transform(md5_info, salt2, 32); ssl_md5_complete(md5_info, out); ssl_md5_info_delete(md5_info); } /*****************************************************************************/ static void APP_CC xrdp_sec_establish_keys(struct xrdp_sec* self) { char session_key[48]; char temp_hash[48]; char input[48]; g_memcpy(input, self->client_random, 24); g_memcpy(input + 24, self->server_random, 24); xrdp_sec_hash_48(temp_hash, input, self->client_random, self->server_random, 65); xrdp_sec_hash_48(session_key, temp_hash, self->client_random, self->server_random, 88); g_memcpy(self->sign_key, session_key, 16); xrdp_sec_hash_16(self->encrypt_key, session_key + 16, self->client_random, self->server_random); xrdp_sec_hash_16(self->decrypt_key, session_key + 32, self->client_random, self->server_random); if (self->rc4_key_size == 1) { xrdp_sec_make_40bit(self->sign_key); xrdp_sec_make_40bit(self->encrypt_key); xrdp_sec_make_40bit(self->decrypt_key); self->rc4_key_len = 8; } else { self->rc4_key_len = 16; } g_memcpy(self->decrypt_update_key, self->decrypt_key, 16); g_memcpy(self->encrypt_update_key, self->encrypt_key, 16); ssl_rc4_set_key(self->decrypt_rc4_info, self->decrypt_key, self->rc4_key_len); ssl_rc4_set_key(self->encrypt_rc4_info, self->encrypt_key, self->rc4_key_len); } /*****************************************************************************/ /* returns error */ int APP_CC xrdp_sec_recv(struct xrdp_sec* self, struct stream* s, int* chan) { int flags; int len; DEBUG((" in xrdp_sec_recv")); if (xrdp_mcs_recv(self->mcs_layer, s, chan) != 0) { DEBUG((" out xrdp_sec_recv error")); return 1; } in_uint32_le(s, flags); DEBUG((" in xrdp_sec_recv flags $%x", flags)); if (flags & SEC_ENCRYPT) /* 0x08 */ { in_uint8s(s, 8); /* signature */ xrdp_sec_decrypt(self, s->p, (int)(s->end - s->p)); } if (flags & SEC_CLIENT_RANDOM) /* 0x01 */ { in_uint32_le(s, len); in_uint8a(s, self->client_crypt_random, 64); xrdp_sec_rsa_op(self->client_random, self->client_crypt_random, self->pub_mod, self->pri_exp); xrdp_sec_establish_keys(self); *chan = 1; /* just set a non existing channel and exit */ DEBUG((" out xrdp_sec_recv")); return 0; } if (flags & SEC_LOGON_INFO) /* 0x40 */ { if (xrdp_sec_process_logon_info(self, s) != 0) { DEBUG((" out xrdp_sec_recv error")); return 1; } if (self->rdp_layer->client_info.is_mce) { if (xrdp_sec_send_media_lic_response(self) != 0) { DEBUG((" out xrdp_sec_recv error")); return 1; } DEBUG((" out xrdp_sec_recv")); return -1; /* special error that means send demand active */ } if (xrdp_sec_send_lic_initial(self) != 0) { DEBUG((" out xrdp_sec_recv error")); return 1; } *chan = 1; /* just set a non existing channel and exit */ DEBUG((" out xrdp_sec_recv")); return 0; } if (flags & SEC_LICENCE_NEG) /* 0x80 */ { if (xrdp_sec_send_lic_response(self) != 0) { DEBUG((" out xrdp_sec_recv error")); return 1; } DEBUG((" out xrdp_sec_recv")); return -1; /* special error that means send demand active */ } DEBUG((" out xrdp_sec_recv")); return 0; } /*****************************************************************************/ /* Output a uint32 into a buffer (little-endian) */ static void buf_out_uint32(char* buffer, int value) { buffer[0] = (value) & 0xff; buffer[1] = (value >> 8) & 0xff; buffer[2] = (value >> 16) & 0xff; buffer[3] = (value >> 24) & 0xff; } /*****************************************************************************/ /* Generate a MAC hash (5.2.3.1), using a combination of SHA1 and MD5 */ static void APP_CC xrdp_sec_sign(struct xrdp_sec* self, char* out, int out_len, char* data, int data_len) { char shasig[20]; char md5sig[16]; char lenhdr[4]; void* sha1_info; void* md5_info; buf_out_uint32(lenhdr, data_len); sha1_info = ssl_sha1_info_create(); md5_info = ssl_md5_info_create(); ssl_sha1_clear(sha1_info); ssl_sha1_transform(sha1_info, self->sign_key, self->rc4_key_len); ssl_sha1_transform(sha1_info, (char*)g_pad_54, 40); ssl_sha1_transform(sha1_info, lenhdr, 4); ssl_sha1_transform(sha1_info, data, data_len); ssl_sha1_complete(sha1_info, shasig); ssl_md5_clear(md5_info); ssl_md5_transform(md5_info, self->sign_key, self->rc4_key_len); ssl_md5_transform(md5_info, (char*)g_pad_92, 48); ssl_md5_transform(md5_info, shasig, 20); ssl_md5_complete(md5_info, md5sig); g_memcpy(out, md5sig, out_len); ssl_sha1_info_delete(sha1_info); ssl_md5_info_delete(md5_info); } /*****************************************************************************/ /* returns error */ int APP_CC xrdp_sec_send(struct xrdp_sec* self, struct stream* s, int chan) { int datalen; DEBUG((" in xrdp_sec_send")); s_pop_layer(s, sec_hdr); if (self->crypt_level > 1) { out_uint32_le(s, SEC_ENCRYPT); datalen = (int)((s->end - s->p) - 8); xrdp_sec_sign(self, s->p, 8, s->p + 8, datalen); xrdp_sec_encrypt(self, s->p + 8, datalen); } else { out_uint32_le(s, 0); } if (xrdp_mcs_send(self->mcs_layer, s, chan) != 0) { return 1; } DEBUG((" out xrdp_sec_send")); return 0; } /*****************************************************************************/ /* this adds the mcs channels in the list of channels to be used when creating the server mcs data */ static int APP_CC xrdp_sec_process_mcs_data_channels(struct xrdp_sec* self, struct stream* s) { int num_channels; int index; struct mcs_channel_item* channel_item; DEBUG(("processing channels, channel_code is %d", self->channel_code)); /* this is an option set in xrdp.ini */ if (self->channel_code != 1) /* are channels on? */ { return 0; } in_uint32_le(s, num_channels); for (index = 0; index < num_channels; index++) { channel_item = (struct mcs_channel_item*) g_malloc(sizeof(struct mcs_channel_item), 1); in_uint8a(s, channel_item->name, 8); in_uint32_be(s, channel_item->flags); channel_item->chanid = MCS_GLOBAL_CHANNEL + (index + 1); list_add_item(self->mcs_layer->channel_list, (long)channel_item); DEBUG(("got channel flags %8.8x name %s", channel_item->flags, channel_item->name)); } return 0; } /*****************************************************************************/ /* process client mcs data, we need some things in here to create the server mcs data */ int APP_CC xrdp_sec_process_mcs_data(struct xrdp_sec* self) { struct stream* s = (struct stream *)NULL; char* hold_p = (char *)NULL; int tag = 0; int size = 0; s = &self->client_mcs_data; /* set p to beginning */ s->p = s->data; /* skip header */ in_uint8s(s, 23); while (s_check_rem(s, 4)) { hold_p = s->p; in_uint16_le(s, tag); in_uint16_le(s, size); if (size < 4 || !s_check_rem(s, size - 4)) { g_writeln("error in xrdp_sec_process_mcs_data tag %d size %d", tag, size); break; } switch (tag) { case SEC_TAG_CLI_INFO: break; case SEC_TAG_CLI_CRYPT: break; case SEC_TAG_CLI_CHANNELS: xrdp_sec_process_mcs_data_channels(self, s); break; case SEC_TAG_CLI_4: break; default: g_writeln("error unknown xrdp_sec_process_mcs_data tag %d size %d", tag, size); break; } s->p = hold_p + size; } /* set p to beginning */ s->p = s->data; return 0; } /*****************************************************************************/ /* prepare server mcs data to send in mcs layer */ int APP_CC xrdp_sec_out_mcs_data(struct xrdp_sec* self) { struct stream* s; int num_channels_even; int num_channels; int index; int channel; num_channels = self->mcs_layer->channel_list->count; num_channels_even = num_channels + (num_channels & 1); s = &self->server_mcs_data; init_stream(s, 512); out_uint16_be(s, 5); out_uint16_be(s, 0x14); out_uint8(s, 0x7c); out_uint16_be(s, 1); out_uint8(s, 0x2a); out_uint8(s, 0x14); out_uint8(s, 0x76); out_uint8(s, 0x0a); out_uint8(s, 1); out_uint8(s, 1); out_uint8(s, 0); out_uint16_le(s, 0xc001); out_uint8(s, 0); out_uint8(s, 0x4d); /* M */ out_uint8(s, 0x63); /* c */ out_uint8(s, 0x44); /* D */ out_uint8(s, 0x6e); /* n */ out_uint16_be(s, 0x80fc + (num_channels_even * 2)); out_uint16_le(s, SEC_TAG_SRV_INFO); out_uint16_le(s, 8); /* len */ out_uint8(s, 4); /* 4 = rdp5 1 = rdp4 */ out_uint8(s, 0); out_uint8(s, 8); out_uint8(s, 0); out_uint16_le(s, SEC_TAG_SRV_CHANNELS); out_uint16_le(s, 8 + (num_channels_even * 2)); /* len */ out_uint16_le(s, MCS_GLOBAL_CHANNEL); /* 1003, 0x03eb main channel */ out_uint16_le(s, num_channels); /* number of other channels */ for (index = 0; index < num_channels_even; index++) { if (index < num_channels) { channel = MCS_GLOBAL_CHANNEL + (index + 1); out_uint16_le(s, channel); } else { out_uint16_le(s, 0); } } out_uint16_le(s, SEC_TAG_SRV_CRYPT); out_uint16_le(s, 0x00ec); /* len is 236 */ out_uint32_le(s, self->rc4_key_size); /* key len 1 = 40 bit 2 = 128 bit */ out_uint32_le(s, self->crypt_level); /* crypt level 1 = low 2 = medium */ /* 3 = high */ out_uint32_le(s, 32); /* 32 bytes random len */ out_uint32_le(s, 0xb8); /* 184 bytes rsa info(certificate) len */ out_uint8a(s, self->server_random, 32); /* here to end is certificate */ /* HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\ */ /* TermService\Parameters\Certificate */ out_uint32_le(s, 1); out_uint32_le(s, 1); out_uint32_le(s, 1); out_uint16_le(s, SEC_TAG_PUBKEY); out_uint16_le(s, 0x005c); /* 92 bytes length of SEC_TAG_PUBKEY */ out_uint32_le(s, SEC_RSA_MAGIC); out_uint32_le(s, 0x48); /* 72 bytes modulus len */ out_uint32_be(s, 0x00020000); out_uint32_be(s, 0x3f000000); out_uint8a(s, self->pub_exp, 4); /* pub exp */ out_uint8a(s, self->pub_mod, 64); /* pub mod */ out_uint8s(s, 8); /* pad */ out_uint16_le(s, SEC_TAG_KEYSIG); out_uint16_le(s, 72); /* len */ out_uint8a(s, self->pub_sig, 64); /* pub sig */ out_uint8s(s, 8); /* pad */ /* end certificate */ s_mark_end(s); return 0; } /*****************************************************************************/ /* process the mcs client data we received from the mcs layer */ static void APP_CC xrdp_sec_in_mcs_data(struct xrdp_sec* self) { struct stream* s = (struct stream *)NULL; struct xrdp_client_info* client_info = (struct xrdp_client_info *)NULL; int index = 0; char c = 0; client_info = &(self->rdp_layer->client_info); s = &(self->client_mcs_data); /* get hostname, its unicode */ s->p = s->data; in_uint8s(s, 47); g_memset(client_info->hostname, 0, 32); c = 1; index = 0; while (index < 16 && c != 0) { in_uint8(s, c); in_uint8s(s, 1); client_info->hostname[index] = c; index++; } /* get build */ s->p = s->data; in_uint8s(s, 43); in_uint32_le(s, client_info->build); /* get keylayout */ s->p = s->data; in_uint8s(s, 39); in_uint32_le(s, client_info->keylayout); s->p = s->data; } /*****************************************************************************/ int APP_CC xrdp_sec_incoming(struct xrdp_sec* self) { struct list* items = NULL; struct list* values = NULL; int index = 0; char* item = NULL; char* value = NULL; char key_file[256]; g_memset(key_file,0,sizeof(char)*256); DEBUG((" in xrdp_sec_incoming")); g_random(self->server_random, 32); items = list_create(); items->auto_free = 1; values = list_create(); values->auto_free = 1; g_snprintf(key_file, 255, "%s/rsakeys.ini", XRDP_CFG_PATH); if (file_by_name_read_section(key_file, "keys", items, values) != 0) { /* this is a show stopper */ g_writeln("xrdp_sec_incoming: error reading %s file", key_file); list_delete(items); list_delete(values); return 1; } for (index = 0; index < items->count; index++) { item = (char*)list_get_item(items, index); value = (char*)list_get_item(values, index); if (g_strcasecmp(item, "pub_exp") == 0) { hex_str_to_bin(value, self->pub_exp, 4); } else if (g_strcasecmp(item, "pub_mod") == 0) { hex_str_to_bin(value, self->pub_mod, 64); } else if (g_strcasecmp(item, "pub_sig") == 0) { hex_str_to_bin(value, self->pub_sig, 64); } else if (g_strcasecmp(item, "pri_exp") == 0) { hex_str_to_bin(value, self->pri_exp, 64); } } list_delete(items); list_delete(values); if (xrdp_mcs_incoming(self->mcs_layer) != 0) { return 1; } #ifdef XRDP_DEBUG g_writeln("client mcs data received"); g_hexdump(self->client_mcs_data.data, (int)(self->client_mcs_data.end - self->client_mcs_data.data)); g_writeln("server mcs data sent"); g_hexdump(self->server_mcs_data.data, (int)(self->server_mcs_data.end - self->server_mcs_data.data)); #endif DEBUG((" out xrdp_sec_incoming")); xrdp_sec_in_mcs_data(self); return 0; } /*****************************************************************************/ int APP_CC xrdp_sec_disconnect(struct xrdp_sec* self) { int rv; DEBUG((" in xrdp_sec_disconnect")); rv = xrdp_mcs_disconnect(self->mcs_layer); DEBUG((" out xrdp_sec_disconnect")); return rv; } xrdp-0.6.0/libxrdp/xrdp_tcp.c000066400000000000000000000047061203155130500161270ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2004-2010 tcp layer */ #include "libxrdp.h" /*****************************************************************************/ struct xrdp_tcp* APP_CC xrdp_tcp_create(struct xrdp_iso* owner, struct trans* trans) { struct xrdp_tcp* self; DEBUG((" in xrdp_tcp_create")); self = (struct xrdp_tcp*)g_malloc(sizeof(struct xrdp_tcp), 1); self->iso_layer = owner; self->trans = trans; DEBUG((" out xrdp_tcp_create")); return self; } /*****************************************************************************/ void APP_CC xrdp_tcp_delete(struct xrdp_tcp* self) { g_free(self); } /*****************************************************************************/ /* get out stream ready for data */ /* returns error */ int APP_CC xrdp_tcp_init(struct xrdp_tcp* self, struct stream* s) { init_stream(s, 8192); return 0; } /*****************************************************************************/ /* returns error */ int APP_CC xrdp_tcp_recv(struct xrdp_tcp* self, struct stream* s, int len) { DEBUG((" in xrdp_tcp_recv, gota get %d bytes", len)); init_stream(s, len); if (trans_force_read_s(self->trans, s, len) != 0) { DEBUG((" error in trans_force_read_s")); return 1; } DEBUG((" out xrdp_tcp_recv")); return 0; } /*****************************************************************************/ /* returns error */ int APP_CC xrdp_tcp_send(struct xrdp_tcp* self, struct stream* s) { int len; len = s->end - s->data; DEBUG((" in xrdp_tcp_send, gota send %d bytes", len)); if (trans_force_write_s(self->trans, s) != 0) { DEBUG((" error in trans_force_write_s")); return 1; } DEBUG((" out xrdp_tcp_send, sent %d bytes ok", len)); return 0; } xrdp-0.6.0/mc/000077500000000000000000000000001203155130500130645ustar00rootroot00000000000000xrdp-0.6.0/mc/Makefile.am000066400000000000000000000005361203155130500151240ustar00rootroot00000000000000EXTRA_DIST = mc.h AM_CFLAGS = \ -DXRDP_CFG_PATH=\"${sysconfdir}/xrdp\" \ -DXRDP_SBIN_PATH=\"${sbindir}\" \ -DXRDP_SHARE_PATH=\"${datadir}/xrdp\" \ -DXRDP_PID_PATH=\"${localstatedir}/run\" INCLUDES = \ -I$(top_srcdir)/common lib_LTLIBRARIES = \ libmc.la libmc_la_SOURCES = mc.c libmc_la_LIBADD = \ $(top_srcdir)/common/libcommon.la xrdp-0.6.0/mc/mc.c000066400000000000000000000056671203155130500136450ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2007-2010 media center */ #include "mc.h" /*****************************************************************************/ /* return error */ int DEFAULT_CC lib_mod_start(struct mod* mod, int w, int h, int bpp) { LIB_DEBUG(mod, "in lib_mod_start"); mod->width = w; mod->height = h; mod->bpp = bpp; LIB_DEBUG(mod, "out lib_mod_start"); return 0; } /******************************************************************************/ /* return error */ int DEFAULT_CC lib_mod_connect(struct mod* mod) { LIB_DEBUG(mod, "in lib_mod_connect"); LIB_DEBUG(mod, "out lib_mod_connect"); return 0; } /******************************************************************************/ /* return error */ int DEFAULT_CC lib_mod_event(struct mod* mod, int msg, long param1, long param2, long param3, long param4) { LIB_DEBUG(mod, "in lib_mod_event"); LIB_DEBUG(mod, "out lib_mod_event"); return 0; } /******************************************************************************/ /* return error */ int DEFAULT_CC lib_mod_signal(struct mod* mod) { LIB_DEBUG(mod, "in lib_mod_signal"); LIB_DEBUG(mod, "out lib_mod_signal"); return 0; } /******************************************************************************/ /* return error */ int DEFAULT_CC lib_mod_end(struct mod* mod) { return 0; } /******************************************************************************/ /* return error */ int DEFAULT_CC lib_mod_set_param(struct mod* mod, char* name, char* value) { return 0; } /******************************************************************************/ struct mod* EXPORT_CC mod_init(void) { struct mod* mod; mod = (struct mod*)g_malloc(sizeof(struct mod), 1); mod->size = sizeof(struct mod); mod->version = CURRENT_MOD_VER; mod->handle = (long)mod; mod->mod_connect = lib_mod_connect; mod->mod_start = lib_mod_start; mod->mod_event = lib_mod_event; mod->mod_signal = lib_mod_signal; mod->mod_end = lib_mod_end; mod->mod_set_param = lib_mod_set_param; return mod; } /******************************************************************************/ int EXPORT_CC mod_exit(struct mod* mod) { if (mod == 0) { return 0; } g_free(mod); return 0; } xrdp-0.6.0/mc/mc.h000066400000000000000000000104611203155130500136360ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2007-2010 media center */ /* include other h files */ #include "arch.h" #include "parse.h" #include "os_calls.h" #include "defines.h" #define CURRENT_MOD_VER 2 struct mod { int size; /* size of this struct */ int version; /* internal version */ /* client functions */ int (*mod_start)(struct mod* v, int w, int h, int bpp); int (*mod_connect)(struct mod* v); int (*mod_event)(struct mod* v, int msg, long param1, long param2, long param3, long param4); int (*mod_signal)(struct mod* v); int (*mod_end)(struct mod* v); int (*mod_set_param)(struct mod* v, char* name, char* value); int (*mod_session_change)(struct mod* v, int, int); int (*mod_get_wait_objs)(struct mod* v, tbus* read_objs, int* rcount, tbus* write_objs, int* wcount, int* timeout); int (*mod_check_wait_objs)(struct mod* v); long mod_dumby[100 - 9]; /* align, 100 minus the number of mod functions above */ /* server functions */ int (*server_begin_update)(struct mod* v); int (*server_end_update)(struct mod* v); int (*server_fill_rect)(struct mod* v, int x, int y, int cx, int cy); int (*server_screen_blt)(struct mod* v, int x, int y, int cx, int cy, int srcx, int srcy); int (*server_paint_rect)(struct mod* v, int x, int y, int cx, int cy, char* data, int width, int height, int srcx, int srcy); int (*server_set_cursor)(struct mod* v, int x, int y, char* data, char* mask); int (*server_palette)(struct mod* v, int* palette); int (*server_msg)(struct mod* v, char* msg, int code); int (*server_is_term)(struct mod* v); int (*server_set_clip)(struct mod* v, int x, int y, int cx, int cy); int (*server_reset_clip)(struct mod* v); int (*server_set_fgcolor)(struct mod* v, int fgcolor); int (*server_set_bgcolor)(struct mod* v, int bgcolor); int (*server_set_opcode)(struct mod* v, int opcode); int (*server_set_mixmode)(struct mod* v, int mixmode); int (*server_set_brush)(struct mod* v, int x_orgin, int y_orgin, int style, char* pattern); int (*server_set_pen)(struct mod* v, int style, int width); int (*server_draw_line)(struct mod* v, int x1, int y1, int x2, int y2); int (*server_add_char)(struct mod* v, int font, int charactor, int offset, int baseline, int width, int height, char* data); int (*server_draw_text)(struct mod* v, int font, int flags, int mixmode, int clip_left, int clip_top, int clip_right, int clip_bottom, int box_left, int box_top, int box_right, int box_bottom, int x, int y, char* data, int data_len); int (*server_reset)(struct mod* v, int width, int height, int bpp); int (*server_query_channel)(struct mod* v, int index, char* channel_name, int* channel_flags); int (*server_get_channel_id)(struct mod* v, char* name); int (*server_send_to_channel)(struct mod* v, int channel_id, char* data, int data_len, int total_data_len, int flags); int (*server_bell_trigger)(struct mod* v); long server_dumby[100 - 25]; /* align, 100 minus the number of server functions above */ /* common */ long handle; /* pointer to self as long */ long wm; long painter; int sck; /* mod data */ int width; int height; int bpp; }; xrdp-0.6.0/prog_std.txt000066400000000000000000000014451203155130500150530ustar00rootroot00000000000000 This is an atempt to explain my odd programming standard used for this project. Not to defend any of these but its my default standard and make it easy for me to read. Some files break these rules, they will be updated eventually. try to make any file compile with c++ compilers always put one var on a line by itself char* pvar; char text[256]; not char *pvar, text[256]; function calls look like this foo(a, b, c); not foo ( a, b, c ); while, if, and case statements look like while (i != 0) not while(i != 0) for comments, always use /* */, not // defines should always be uppercase don't use tabs, use spaces no line should exceed 80 chars always use {} in if and while, even if its only one line while (p != 0) { p = p->next; } not while (p != 0) p = p->next; xrdp-0.6.0/rdp/000077500000000000000000000000001203155130500132525ustar00rootroot00000000000000xrdp-0.6.0/rdp/Makefile.am000066400000000000000000000007351203155130500153130ustar00rootroot00000000000000EXTRA_DIST = rdp.h AM_CFLAGS = \ -DXRDP_CFG_PATH=\"${sysconfdir}/xrdp\" \ -DXRDP_SBIN_PATH=\"${sbindir}\" \ -DXRDP_SHARE_PATH=\"${datadir}/xrdp\" \ -DXRDP_PID_PATH=\"${localstatedir}/run\" INCLUDES = \ -I$(top_srcdir)/common lib_LTLIBRARIES = \ librdp.la librdp_la_SOURCES = \ rdp.c \ rdp_bitmap.c \ rdp_iso.c \ rdp_lic.c \ rdp_mcs.c \ rdp_orders.c \ rdp_rdp.c \ rdp_sec.c \ rdp_tcp.c librdp_la_LIBADD = \ $(top_srcdir)/common/libcommon.la xrdp-0.6.0/rdp/rdp.c000066400000000000000000000214211203155130500142030ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2005-2010 librdp main file */ #include "rdp.h" /******************************************************************************/ /* return error */ int DEFAULT_CC lib_mod_start(struct mod* mod, int w, int h, int bpp) { DEBUG(("in lib_mod_start")); mod->width = w; mod->height = h; mod->rdp_bpp = bpp; mod->xrdp_bpp = bpp; mod->keylayout = 0x409; g_strncpy(mod->port, "3389", 255); /* default */ DEBUG(("out lib_mod_start")); return 0; } /******************************************************************************/ /* return error */ int DEFAULT_CC lib_mod_connect(struct mod* mod) { DEBUG(("in lib_mod_connect")); /* clear screen */ mod->server_begin_update(mod); mod->server_set_fgcolor(mod, 0); mod->server_fill_rect(mod, 0, 0, mod->width, mod->height); mod->server_end_update(mod); /* connect */ if (rdp_rdp_connect(mod->rdp_layer, mod->ip, mod->port) == 0) { mod->sck = mod->rdp_layer->sec_layer->mcs_layer->iso_layer->tcp_layer->sck; g_tcp_set_non_blocking(mod->sck); g_tcp_set_no_delay(mod->sck); mod->sck_obj = g_create_wait_obj_from_socket(mod->sck, 0); DEBUG(("out lib_mod_connect")); return 0; } DEBUG(("out lib_mod_connect error")); return 1; } /******************************************************************************/ /* return error */ int DEFAULT_CC lib_mod_event(struct mod* mod, int msg, long param1, long param2, long param3, long param4) { struct stream* s; if (!mod->up_and_running) { return 0; } DEBUG(("in lib_mod_event")); make_stream(s); init_stream(s, 8192 * 2); switch (msg) { case 15: rdp_rdp_send_input(mod->rdp_layer, s, 0, RDP_INPUT_SCANCODE, param4, param3, 0); break; case 16: rdp_rdp_send_input(mod->rdp_layer, s, 0, RDP_INPUT_SCANCODE, param4, param3, 0); break; case 17: rdp_rdp_send_input(mod->rdp_layer, s, 0, RDP_INPUT_SYNCHRONIZE, param4, param3, 0); break; case 100: rdp_rdp_send_input(mod->rdp_layer, s, 0, RDP_INPUT_MOUSE, MOUSE_FLAG_MOVE, param1, param2); break; case 101: rdp_rdp_send_input(mod->rdp_layer, s, 0, RDP_INPUT_MOUSE, MOUSE_FLAG_BUTTON1, param1, param2); break; case 102: rdp_rdp_send_input(mod->rdp_layer, s, 0, RDP_INPUT_MOUSE, MOUSE_FLAG_BUTTON1 | MOUSE_FLAG_DOWN, param1, param2); break; case 103: rdp_rdp_send_input(mod->rdp_layer, s, 0, RDP_INPUT_MOUSE, MOUSE_FLAG_BUTTON2, param1, param2); break; case 104: rdp_rdp_send_input(mod->rdp_layer, s, 0, RDP_INPUT_MOUSE, MOUSE_FLAG_BUTTON2 | MOUSE_FLAG_DOWN, param1, param2); break; case 105: rdp_rdp_send_input(mod->rdp_layer, s, 0, RDP_INPUT_MOUSE, MOUSE_FLAG_BUTTON3, param1, param2); break; case 106: rdp_rdp_send_input(mod->rdp_layer, s, 0, RDP_INPUT_MOUSE, MOUSE_FLAG_BUTTON3 | MOUSE_FLAG_DOWN, param1, param2); break; case 107: rdp_rdp_send_input(mod->rdp_layer, s, 0, RDP_INPUT_MOUSE, MOUSE_FLAG_BUTTON4, param1, param2); break; case 108: rdp_rdp_send_input(mod->rdp_layer, s, 0, RDP_INPUT_MOUSE, MOUSE_FLAG_BUTTON4 | MOUSE_FLAG_DOWN, param1, param2); break; case 109: rdp_rdp_send_input(mod->rdp_layer, s, 0, RDP_INPUT_MOUSE, MOUSE_FLAG_BUTTON5, param1, param2); break; case 110: rdp_rdp_send_input(mod->rdp_layer, s, 0, RDP_INPUT_MOUSE, MOUSE_FLAG_BUTTON5 | MOUSE_FLAG_DOWN, param1, param2); break; case 200: rdp_rdp_send_invalidate(mod->rdp_layer, s, (param1 >> 16) & 0xffff, param1 & 0xffff, (param2 >> 16) & 0xffff, param2 & 0xffff); break; } free_stream(s); DEBUG(("out lib_mod_event")); return 0; } /******************************************************************************/ /* return error */ int DEFAULT_CC lib_mod_signal(struct mod* mod) { int type; int cont; struct stream* s; DEBUG(("in lib_mod_signal")); if (mod->in_s == 0) { make_stream(mod->in_s); } s = mod->in_s; init_stream(s, 8192 * 2); cont = 1; while (cont) { type = 0; if (rdp_rdp_recv(mod->rdp_layer, s, &type) != 0) { DEBUG(("out lib_mod_signal error rdp_rdp_recv failed")); return 1; } DEBUG(("lib_mod_signal type %d", type)); switch (type) { case RDP_PDU_DATA: rdp_rdp_process_data_pdu(mod->rdp_layer, s); break; case RDP_PDU_DEMAND_ACTIVE: rdp_rdp_process_demand_active(mod->rdp_layer, s); mod->up_and_running = 1; break; case RDP_PDU_DEACTIVATE: mod->up_and_running = 0; break; case RDP_PDU_REDIRECT: break; case 0: break; default: break; } cont = s->next_packet < s->end; } DEBUG(("out lib_mod_signal")); return 0; } /******************************************************************************/ /* return error */ int DEFAULT_CC lib_mod_end(struct mod* mod) { rdp_rdp_delete(mod->rdp_layer); mod->rdp_layer = 0; free_stream(mod->in_s); mod->in_s = 0; if (mod->sck_obj != 0) { g_delete_wait_obj_from_socket(mod->sck_obj); mod->sck_obj = 0; } if (mod->sck != 0) { g_tcp_close(mod->sck); mod->sck = 0; } return 0; } /******************************************************************************/ /* return error */ int DEFAULT_CC lib_mod_set_param(struct mod* mod, char* name, char* value) { if (g_strncasecmp(name, "ip", 255) == 0) { g_strncpy(mod->ip, value, 255); } else if (g_strncasecmp(name, "port", 255) == 0) { g_strncpy(mod->port, value, 255); } else if (g_strncasecmp(name, "username", 255) == 0) { g_strncpy(mod->username, value, 255); } else if (g_strncasecmp(name, "password", 255) == 0) { g_strncpy(mod->password, value, 255); } else if (g_strncasecmp(name, "hostname", 255) == 0) { g_strncpy(mod->hostname, value, 255); } else if (g_strncasecmp(name, "keylayout", 255) == 0) { mod->keylayout = g_atoi(value); } return 0; } /******************************************************************************/ /* return error */ int DEFAULT_CC lib_mod_get_wait_objs(struct mod* mod, tbus* read_objs, int* rcount, tbus* write_objs, int* wcount, int* timeout) { int i; i = *rcount; if (mod != 0) { if (mod->sck_obj != 0) { read_objs[i++] = mod->sck_obj; } } *rcount = i; return 0; } /******************************************************************************/ /* return error */ int DEFAULT_CC lib_mod_check_wait_objs(struct mod* mod) { int rv; rv = 0; if (mod != 0) { if (mod->sck_obj != 0) { if (g_is_wait_obj_set(mod->sck_obj)) { rv = lib_mod_signal(mod); } } } return rv; } /******************************************************************************/ struct mod* EXPORT_CC mod_init(void) { struct mod* mod; DEBUG(("in mod_init")); mod = (struct mod*)g_malloc(sizeof(struct mod), 1); mod->size = sizeof(struct mod); mod->version = CURRENT_MOD_VER; mod->handle = (long)mod; mod->mod_connect = lib_mod_connect; mod->mod_start = lib_mod_start; mod->mod_event = lib_mod_event; mod->mod_signal = lib_mod_signal; mod->mod_end = lib_mod_end; mod->mod_set_param = lib_mod_set_param; mod->mod_get_wait_objs = lib_mod_get_wait_objs; mod->mod_check_wait_objs = lib_mod_check_wait_objs; mod->rdp_layer = rdp_rdp_create(mod); DEBUG(("out mod_init")); return mod; } /******************************************************************************/ int EXPORT_CC mod_exit(struct mod* mod) { DEBUG(("in mod_exit")); g_free(mod); DEBUG(("out mod_exit")); return 0; } xrdp-0.6.0/rdp/rdp.h000066400000000000000000000310111203155130500142040ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2005-2010 librdp main header file */ /* include other h files */ #include "arch.h" #include "parse.h" #include "os_calls.h" #include "ssl_calls.h" #include "xrdp_constants.h" #include "defines.h" struct rdp_brush { int xorigin; int yorigin; int style; char pattern[8]; }; struct rdp_pen { int style; int width; int color; }; struct rdp_colormap { int ncolors; int colors[256]; }; struct rdp_bitmap { int width; int height; int bpp; char* data; }; struct rdp_cursor { int x; int y; int width; int height; char mask[(32 * 32) / 8]; char data[(32 * 32) * 3]; }; /* tcp */ struct rdp_tcp { int sck; int sck_closed; struct rdp_iso* iso_layer; /* owner */ }; /* iso */ struct rdp_iso { struct rdp_mcs* mcs_layer; /* owner */ struct rdp_tcp* tcp_layer; }; /* mcs */ struct rdp_mcs { struct rdp_sec* sec_layer; /* owner */ struct rdp_iso* iso_layer; int userid; struct stream* client_mcs_data; struct stream* server_mcs_data; }; /* sec */ struct rdp_sec { struct rdp_rdp* rdp_layer; /* owner */ struct rdp_mcs* mcs_layer; struct rdp_lic* lic_layer; char server_random[32]; char client_random[64]; char client_crypt_random[72]; struct stream* client_mcs_data; struct stream* server_mcs_data; int decrypt_use_count; int encrypt_use_count; char decrypt_key[16]; char encrypt_key[16]; char decrypt_update_key[16]; char encrypt_update_key[16]; int rc4_key_size; /* 1 = 40-bit, 2 = 128-bit */ int rc4_key_len; /* 8 or 16 */ int crypt_level; /* 1 = low, 2 = medium, 3 = high */ char sign_key[16]; void* decrypt_rc4_info; void* encrypt_rc4_info; }; /* licence */ struct rdp_lic { struct rdp_sec* sec_layer; /* owner */ char licence_key[16]; char licence_sign_key[16]; int licence_issued; }; /* rdp */ struct rdp_rdp { struct mod* mod; struct rdp_sec* sec_layer; struct rdp_orders* orders; int share_id; int use_rdp5; int bitmap_compression; int bitmap_cache; int desktop_save; int polygon_ellipse_orders; int rec_mode; int rec_fd; /* cache */ struct rdp_colormap colormap; struct rdp_cursor cursors[32]; }; struct rdp_orders_state { /* order stuff */ int order_type; /* clip state */ int clip_left; int clip_top; int clip_right; int clip_bottom; /* text order state */ int text_font; int text_flags; int text_opcode; int text_mixmode; int text_fgcolor; int text_bgcolor; int text_clipleft; int text_cliptop; int text_clipright; int text_clipbottom; int text_boxleft; int text_boxtop; int text_boxright; int text_boxbottom; struct rdp_brush text_brush; int text_x; int text_y; int text_length; char text_text[256]; /* destblt order state */ int dest_x; int dest_y; int dest_cx; int dest_cy; int dest_opcode; /* patblt order state */ int pat_x; int pat_y; int pat_cx; int pat_cy; int pat_opcode; int pat_bgcolor; int pat_fgcolor; struct rdp_brush pat_brush; /* screenblt order state */ int screenblt_x; int screenblt_y; int screenblt_cx; int screenblt_cy; int screenblt_opcode; int screenblt_srcx; int screenblt_srcy; /* line order state */ int line_mixmode; int line_startx; int line_starty; int line_endx; int line_endy; int line_bgcolor; int line_opcode; struct rdp_pen line_pen; /* rect order state */ int rect_x; int rect_y; int rect_cx; int rect_cy; int rect_color; /* desksave order state */ int desksave_offset; int desksave_left; int desksave_top; int desksave_right; int desksave_bottom; int desksave_action; /* memblt order state */ int memblt_cache_id; int memblt_color_table; int memblt_x; int memblt_y; int memblt_cx; int memblt_cy; int memblt_opcode; int memblt_srcx; int memblt_srcy; int memblt_cache_idx; /* polyline order state */ int polyline_x; int polyline_y; int polyline_opcode; int polyline_fgcolor; int polyline_lines; int polyline_datasize; char polyline_data[256]; }; /* orders */ struct rdp_orders { struct rdp_rdp* rdp_layer; /* order state */ struct rdp_orders_state state; /* cache */ struct rdp_colormap* cache_colormap[6]; struct rdp_bitmap* cache_bitmap[3][600]; }; #define CURRENT_MOD_VER 2 struct mod { int size; /* size of this struct */ int version; /* internal version */ /* client functions */ int (*mod_start)(struct mod* v, int w, int h, int bpp); int (*mod_connect)(struct mod* v); int (*mod_event)(struct mod* v, int msg, long param1, long param2, long param3, long param4); int (*mod_signal)(struct mod* v); int (*mod_end)(struct mod* v); int (*mod_set_param)(struct mod* v, char* name, char* value); int (*mod_session_change)(struct mod* v, int, int); int (*mod_get_wait_objs)(struct mod* v, tbus* read_objs, int* rcount, tbus* write_objs, int* wcount, int* timeout); int (*mod_check_wait_objs)(struct mod* v); long mod_dumby[100 - 9]; /* align, 100 minus the number of mod functions above */ /* server functions */ int (*server_begin_update)(struct mod* v); int (*server_end_update)(struct mod* v); int (*server_fill_rect)(struct mod* v, int x, int y, int cx, int cy); int (*server_screen_blt)(struct mod* v, int x, int y, int cx, int cy, int srcx, int srcy); int (*server_paint_rect)(struct mod* v, int x, int y, int cx, int cy, char* data, int width, int height, int srcx, int srcy); int (*server_set_cursor)(struct mod* v, int x, int y, char* data, char* mask); int (*server_palette)(struct mod* v, int* palette); int (*server_msg)(struct mod* v, char* msg, int code); int (*server_is_term)(struct mod* v); int (*server_set_clip)(struct mod* v, int x, int y, int cx, int cy); int (*server_reset_clip)(struct mod* v); int (*server_set_fgcolor)(struct mod* v, int fgcolor); int (*server_set_bgcolor)(struct mod* v, int bgcolor); int (*server_set_opcode)(struct mod* v, int opcode); int (*server_set_mixmode)(struct mod* v, int mixmode); int (*server_set_brush)(struct mod* v, int x_orgin, int y_orgin, int style, char* pattern); int (*server_set_pen)(struct mod* v, int style, int width); int (*server_draw_line)(struct mod* v, int x1, int y1, int x2, int y2); int (*server_add_char)(struct mod* v, int font, int charactor, int offset, int baseline, int width, int height, char* data); int (*server_draw_text)(struct mod* v, int font, int flags, int mixmode, int clip_left, int clip_top, int clip_right, int clip_bottom, int box_left, int box_top, int box_right, int box_bottom, int x, int y, char* data, int data_len); int (*server_reset)(struct mod* v, int width, int height, int bpp); int (*server_query_channel)(struct mod* v, int index, char* channel_name, int* channel_flags); int (*server_get_channel_id)(struct mod* v, char* name); int (*server_send_to_channel)(struct mod* v, int channel_id, char* data, int data_len, int total_data_len, int flags); int (*server_bell_trigger)(struct mod* v); long server_dumby[100 - 25]; /* align, 100 minus the number of server functions above */ /* common */ long handle; /* pointer to self as long */ long wm; long painter; int sck; /* mod data */ struct rdp_rdp* rdp_layer; int width; int height; int rdp_bpp; int xrdp_bpp; char ip[256]; char port[256]; char username[256]; char password[256]; char hostname[256]; char domain[256]; char program[256]; char directory[256]; int keylayout; int up_and_running; struct stream* in_s; tbus sck_obj; }; /* rdp_tcp.c */ struct rdp_tcp* APP_CC rdp_tcp_create(struct rdp_iso* owner); void APP_CC rdp_tcp_delete(struct rdp_tcp* self); int APP_CC rdp_tcp_init(struct rdp_tcp* self, struct stream* s); int APP_CC rdp_tcp_recv(struct rdp_tcp* self, struct stream* s, int len); int APP_CC rdp_tcp_send(struct rdp_tcp* self, struct stream* s); int APP_CC rdp_tcp_connect(struct rdp_tcp* self, char* ip, char* port); int APP_CC rdp_tcp_disconnect(struct rdp_tcp* self); /* rdp_ico.c */ struct rdp_iso* APP_CC rdp_iso_create(struct rdp_mcs* owner); void APP_CC rdp_iso_delete(struct rdp_iso* self); int APP_CC rdp_iso_recv(struct rdp_iso* self, struct stream* s); int APP_CC rdp_iso_init(struct rdp_iso* self, struct stream* s); int APP_CC rdp_iso_send(struct rdp_iso* self, struct stream* s); int APP_CC rdp_iso_connect(struct rdp_iso* self, char* ip, char* port); int APP_CC rdp_iso_disconnect(struct rdp_iso* self); /* rdp_mcs.c */ struct rdp_mcs* APP_CC rdp_mcs_create(struct rdp_sec* owner, struct stream* client_mcs_data, struct stream* server_mcs_data); void APP_CC rdp_mcs_delete(struct rdp_mcs* self); int APP_CC rdp_mcs_init(struct rdp_mcs* self, struct stream* s); int APP_CC rdp_mcs_send(struct rdp_mcs* self, struct stream* s); int APP_CC rdp_mcs_connect(struct rdp_mcs* self, char* ip, char* port); int APP_CC rdp_mcs_recv(struct rdp_mcs* self, struct stream* s, int* chan); /* rdp_sec.c */ struct rdp_sec* APP_CC rdp_sec_create(struct rdp_rdp* owner); void APP_CC rdp_sec_delete(struct rdp_sec* self); int APP_CC rdp_sec_init(struct rdp_sec* self, struct stream* s, int flags); int APP_CC rdp_sec_send(struct rdp_sec* self, struct stream* s, int flags); int APP_CC rdp_sec_recv(struct rdp_sec* self, struct stream* s, int* chan); int APP_CC rdp_sec_connect(struct rdp_sec* self, char* ip, char* port); void APP_CC rdp_sec_buf_out_uint32(char* buffer, int value); void APP_CC rdp_sec_hash_16(char* out, char* in, char* salt1, char* salt2); void APP_CC rdp_sec_hash_48(char* out, char* in, char* salt1, char* salt2, int salt); void APP_CC rdp_sec_sign(char* signature, int siglen, char* session_key, int keylen, char* data, int datalen); /* rdp_rdp.c */ struct rdp_rdp* APP_CC rdp_rdp_create(struct mod* owner); void APP_CC rdp_rdp_delete(struct rdp_rdp* self); int APP_CC rdp_rdp_connect(struct rdp_rdp* self, char* ip, char* port); int APP_CC rdp_rdp_send_input(struct rdp_rdp* self, struct stream* s, int time, int message_type, int device_flags, int param1, int param2); int APP_CC rdp_rdp_send_invalidate(struct rdp_rdp* self, struct stream* s, int left, int top, int width, int height); int APP_CC rdp_rdp_recv(struct rdp_rdp* self, struct stream* s, int* type); int APP_CC rdp_rdp_process_data_pdu(struct rdp_rdp* self, struct stream* s); int APP_CC rdp_rdp_process_demand_active(struct rdp_rdp* self, struct stream* s); void APP_CC rdp_rdp_out_unistr(struct stream* s, char* text); int APP_CC rdp_rec_check_file(struct rdp_rdp* self); int APP_CC rdp_rec_write_item(struct rdp_rdp* self, struct stream* s); /* rdp_bitmap.c */ int APP_CC rdp_bitmap_decompress(char* output, int width, int height, char* input, int size, int Bpp); /* rdp_orders.c */ struct rdp_orders* APP_CC rdp_orders_create(struct rdp_rdp* owner); void APP_CC rdp_orders_delete(struct rdp_orders* self); void APP_CC rdp_orders_reset_state(struct rdp_orders* self); int APP_CC rdp_orders_process_orders(struct rdp_orders* self, struct stream* s, int num_orders); char* APP_CC rdp_orders_convert_bitmap(int in_bpp, int out_bpp, char* bmpdata, int width, int height, int* palette); int APP_CC rdp_orders_convert_color(int in_bpp, int out_bpp, int in_color, int* palette); /* rdp_lic.c */ struct rdp_lic* APP_CC rdp_lic_create(struct rdp_sec* owner); void APP_CC rdp_lic_delete(struct rdp_lic* self); void APP_CC rdp_lic_process(struct rdp_lic* self, struct stream* s); xrdp-0.6.0/rdp/rdp_bitmap.c000066400000000000000000000500011203155130500155330ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2005-2010 librdp bitmap routines */ #include "rdp.h" /******************************************************************************/ #define CVAL(p) ((unsigned char)(*(p++))) #if defined(B_ENDIAN) #define EIK0 1 #define EIK1 0 #else #define EIK0 0 #define EIK1 1 #endif /******************************************************************************/ #define REPEAT(statement) \ { \ while ((count > 0) && (x < width)) \ { \ statement; \ count--; \ x++; \ } \ } /******************************************************************************/ #define MASK_UPDATE \ { \ mixmask <<= 1; \ if ((mixmask & 0xff) == 0) \ { \ mask = fom_mask ? fom_mask : CVAL(input); \ mixmask = 1; \ } \ } /******************************************************************************/ /* 1 byte bitmap decompress */ /* returns boolean */ static int APP_CC bitmap_decompress1(char* output, int width, int height, char* input, int size) { char* prevline; char* line; char* end; char color1; char color2; char mix; int code; int mixmask; int mask; int opcode; int count; int offset; int isfillormix; int x; int lastopcode; int insertmix; int bicolor; int fom_mask; end = input + size; prevline = 0; line = 0; x = width; lastopcode = -1; insertmix = 0; bicolor = 0; color1 = 0; color2 = 0; mix = 0xff; mask = 0; fom_mask = 0; while (input < end) { fom_mask = 0; code = CVAL(input); opcode = code >> 4; /* Handle different opcode forms */ switch (opcode) { case 0xc: case 0xd: case 0xe: opcode -= 6; count = code & 0xf; offset = 16; break; case 0xf: opcode = code & 0xf; if (opcode < 9) { count = CVAL(input); count |= CVAL(input) << 8; } else { count = (opcode < 0xb) ? 8 : 1; } offset = 0; break; default: opcode >>= 1; count = code & 0x1f; offset = 32; break; } /* Handle strange cases for counts */ if (offset != 0) { isfillormix = ((opcode == 2) || (opcode == 7)); if (count == 0) { if (isfillormix) { count = CVAL(input) + 1; } else { count = CVAL(input) + offset; } } else if (isfillormix) { count <<= 3; } } /* Read preliminary data */ switch (opcode) { case 0: /* Fill */ if ((lastopcode == opcode) && !((x == width) && (prevline == 0))) { insertmix = 1; } break; case 8: /* Bicolor */ color1 = CVAL(input); case 3: /* Color */ color2 = CVAL(input); break; case 6: /* SetMix/Mix */ case 7: /* SetMix/FillOrMix */ mix = CVAL(input); opcode -= 5; break; case 9: /* FillOrMix_1 */ mask = 0x03; opcode = 0x02; fom_mask = 3; break; case 0x0a: /* FillOrMix_2 */ mask = 0x05; opcode = 0x02; fom_mask = 5; break; } lastopcode = opcode; mixmask = 0; /* Output body */ while (count > 0) { if (x >= width) { if (height <= 0) { return 0; } x = 0; height--; prevline = line; line = output + height * width; } switch (opcode) { case 0: /* Fill */ if (insertmix) { if (prevline == 0) { line[x] = mix; } else { line[x] = prevline[x] ^ mix; } insertmix = 0; count--; x++; } if (prevline == 0) { REPEAT(line[x] = 0) } else { REPEAT(line[x] = prevline[x]) } break; case 1: /* Mix */ if (prevline == 0) { REPEAT(line[x] = mix) } else { REPEAT(line[x] = prevline[x] ^ mix) } break; case 2: /* Fill or Mix */ if (prevline == 0) { REPEAT ( MASK_UPDATE; if (mask & mixmask) { line[x] = mix; } else { line[x] = 0; } ) } else { REPEAT ( MASK_UPDATE; if (mask & mixmask) { line[x] = prevline[x] ^ mix; } else { line[x] = prevline[x]; } ) } break; case 3: /* Color */ REPEAT(line[x] = color2) break; case 4: /* Copy */ REPEAT(line[x] = CVAL(input)) break; case 8: /* Bicolor */ REPEAT ( if (bicolor) { line[x] = color2; bicolor = 0; } else { line[x] = color1; bicolor = 1; count++; } ) break; case 0xd: /* White */ REPEAT(line[x] = 0xff) break; case 0xe: /* Black */ REPEAT(line[x] = 0) break; default: return 0; break; } } } return 1; } /******************************************************************************/ /* 2 byte bitmap decompress */ /* returns boolean */ static int APP_CC bitmap_decompress2(char* output, int width, int height, char* input, int size) { char* prevline; char* line; char* end; char color1[2]; char color2[2]; char mix[2]; int code; int mixmask; int mask; int opcode; int count; int offset; int isfillormix; int x; int lastopcode; int insertmix; int bicolor; int fom_mask; end = input + size; prevline = 0; line = 0; x = width; lastopcode = -1; insertmix = 0; bicolor = 0; color1[0] = 0; color1[1] = 0; color2[0] = 0; color2[1] = 0; mix[0] = 0xff; mix[1] = 0xff; mask = 0; fom_mask = 0; while (input < end) { fom_mask = 0; code = CVAL(input); opcode = code >> 4; /* Handle different opcode forms */ switch (opcode) { case 0xc: case 0xd: case 0xe: opcode -= 6; count = code & 0xf; offset = 16; break; case 0xf: opcode = code & 0xf; if (opcode < 9) { count = CVAL(input); count |= CVAL(input) << 8; } else { count = (opcode < 0xb) ? 8 : 1; } offset = 0; break; default: opcode >>= 1; count = code & 0x1f; offset = 32; break; } /* Handle strange cases for counts */ if (offset != 0) { isfillormix = ((opcode == 2) || (opcode == 7)); if (count == 0) { if (isfillormix) { count = CVAL(input) + 1; } else { count = CVAL(input) + offset; } } else if (isfillormix) { count <<= 3; } } /* Read preliminary data */ switch (opcode) { case 0: /* Fill */ if ((lastopcode == opcode) && !((x == width) && (prevline == 0))) { insertmix = 1; } break; case 8: /* Bicolor */ color1[EIK0] = CVAL(input); color1[EIK1] = CVAL(input); case 3: /* Color */ color2[EIK0] = CVAL(input); color2[EIK1] = CVAL(input); break; case 6: /* SetMix/Mix */ case 7: /* SetMix/FillOrMix */ mix[EIK0] = CVAL(input); mix[EIK1] = CVAL(input); opcode -= 5; break; case 9: /* FillOrMix_1 */ mask = 0x03; opcode = 0x02; fom_mask = 3; break; case 0x0a: /* FillOrMix_2 */ mask = 0x05; opcode = 0x02; fom_mask = 5; break; } lastopcode = opcode; mixmask = 0; /* Output body */ while (count > 0) { if (x >= width) { if (height <= 0) { return 0; } x = 0; height--; prevline = line; line = output + height * (width * 2); } switch (opcode) { case 0: /* Fill */ if (insertmix) { if (prevline == 0) { line[x * 2 + 0] = mix[0]; line[x * 2 + 1] = mix[1]; } else { line[x * 2 + 0] = prevline[x * 2 + 0] ^ mix[0]; line[x * 2 + 1] = prevline[x * 2 + 1] ^ mix[1]; } insertmix = 0; count--; x++; } if (prevline == 0) { REPEAT ( line[x * 2 + 0] = 0; line[x * 2 + 1] = 0; ) } else { REPEAT ( line[x * 2 + 0] = prevline[x * 2 + 0]; line[x * 2 + 1] = prevline[x * 2 + 1]; ) } break; case 1: /* Mix */ if (prevline == 0) { REPEAT ( line[x * 2 + 0] = mix[0]; line[x * 2 + 1] = mix[1]; ) } else { REPEAT ( line[x * 2 + 0] = prevline[x * 2 + 0] ^ mix[0]; line[x * 2 + 1] = prevline[x * 2 + 1] ^ mix[1]; ) } break; case 2: /* Fill or Mix */ if (prevline == 0) { REPEAT ( MASK_UPDATE; if (mask & mixmask) { line[x * 2 + 0] = mix[0]; line[x * 2 + 1] = mix[1]; } else { line[x * 2 + 0] = 0; line[x * 2 + 1] = 0; } ) } else { REPEAT ( MASK_UPDATE; if (mask & mixmask) { line[x * 2 + 0] = prevline[x * 2 + 0] ^ mix[0]; line[x * 2 + 1] = prevline[x * 2 + 1] ^ mix[1]; } else { line[x * 2 + 0] = prevline[x * 2 + 0]; line[x * 2 + 1] = prevline[x * 2 + 1]; } ) } break; case 3: /* Color */ REPEAT ( line[x * 2 + 0] = color2[0]; line[x * 2 + 1] = color2[1]; ) break; case 4: /* Copy */ REPEAT ( line[x * 2 + EIK0] = CVAL(input); line[x * 2 + EIK1] = CVAL(input); ) break; case 8: /* Bicolor */ REPEAT ( if (bicolor) { line[x * 2 + 0] = color2[0]; line[x * 2 + 1] = color2[1]; bicolor = 0; } else { line[x * 2 + 0] = color1[0]; line[x * 2 + 1] = color1[1]; bicolor = 1; count++; } ) break; case 0xd: /* White */ REPEAT ( line[x * 2 + 0] = 0xff; line[x * 2 + 1] = 0xff; ) break; case 0xe: /* Black */ REPEAT ( line[x * 2 + 0] = 0; line[x * 2 + 1] = 0; ) break; default: return 0; break; } } } return 1; } /******************************************************************************/ /* 3 byte bitmap decompress */ /* returns boolean */ static int APP_CC bitmap_decompress3(char* output, int width, int height, char* input, int size) { char* prevline; char* line; char* end; char color1[3]; char color2[3]; char mix[3]; int code; int mixmask; int mask; int opcode; int count; int offset; int isfillormix; int x; int lastopcode; int insertmix; int bicolor; int fom_mask; end = input + size; prevline = 0; line = 0; x = width; lastopcode = -1; insertmix = 0; bicolor = 0; color1[0] = 0; color1[1] = 0; color1[2] = 0; color2[0] = 0; color2[1] = 0; color2[2] = 0; mix[0] = 0xff; mix[1] = 0xff; mix[2] = 0xff; mask = 0; fom_mask = 0; while (input < end) { fom_mask = 0; code = CVAL(input); opcode = code >> 4; /* Handle different opcode forms */ switch (opcode) { case 0xc: case 0xd: case 0xe: opcode -= 6; count = code & 0xf; offset = 16; break; case 0xf: opcode = code & 0xf; if (opcode < 9) { count = CVAL(input); count |= CVAL(input) << 8; } else { count = (opcode < 0xb) ? 8 : 1; } offset = 0; break; default: opcode >>= 1; count = code & 0x1f; offset = 32; break; } /* Handle strange cases for counts */ if (offset != 0) { isfillormix = ((opcode == 2) || (opcode == 7)); if (count == 0) { if (isfillormix) { count = CVAL(input) + 1; } else { count = CVAL(input) + offset; } } else if (isfillormix) { count <<= 3; } } /* Read preliminary data */ switch (opcode) { case 0: /* Fill */ if ((lastopcode == opcode) && !((x == width) && (prevline == 0))) { insertmix = 1; } break; case 8: /* Bicolor */ color1[0] = CVAL(input); color1[1] = CVAL(input); color1[2] = CVAL(input); case 3: /* Color */ color2[0] = CVAL(input); color2[1] = CVAL(input); color2[2] = CVAL(input); break; case 6: /* SetMix/Mix */ case 7: /* SetMix/FillOrMix */ mix[0] = CVAL(input); mix[1] = CVAL(input); mix[2] = CVAL(input); opcode -= 5; break; case 9: /* FillOrMix_1 */ mask = 0x03; opcode = 0x02; fom_mask = 3; break; case 0x0a: /* FillOrMix_2 */ mask = 0x05; opcode = 0x02; fom_mask = 5; break; } lastopcode = opcode; mixmask = 0; /* Output body */ while (count > 0) { if (x >= width) { if (height <= 0) { return 0; } x = 0; height--; prevline = line; line = output + height * (width * 3); } switch (opcode) { case 0: /* Fill */ if (insertmix) { if (prevline == 0) { line[x * 3 + 0] = mix[0]; line[x * 3 + 1] = mix[1]; line[x * 3 + 2] = mix[2]; } else { line[x * 3 + 0] = prevline[x * 3 + 0] ^ mix[0]; line[x * 3 + 1] = prevline[x * 3 + 1] ^ mix[1]; line[x * 3 + 2] = prevline[x * 3 + 2] ^ mix[2]; } insertmix = 0; count--; x++; } if (prevline == 0) { REPEAT ( line[x * 3 + 0] = 0; line[x * 3 + 1] = 0; line[x * 3 + 2] = 0; ) } else { REPEAT ( line[x * 3 + 0] = prevline[x * 3 + 0]; line[x * 3 + 1] = prevline[x * 3 + 1]; line[x * 3 + 2] = prevline[x * 3 + 2]; ) } break; case 1: /* Mix */ if (prevline == 0) { REPEAT ( line[x * 3 + 0] = mix[0]; line[x * 3 + 1] = mix[1]; line[x * 3 + 2] = mix[2]; ) } else { REPEAT ( line[x * 3 + 0] = prevline[x * 3 + 0] ^ mix[0]; line[x * 3 + 1] = prevline[x * 3 + 1] ^ mix[1]; line[x * 3 + 2] = prevline[x * 3 + 2] ^ mix[2]; ) } break; case 2: /* Fill or Mix */ if (prevline == 0) { REPEAT ( MASK_UPDATE; if (mask & mixmask) { line[x * 3 + 0] = mix[0]; line[x * 3 + 1] = mix[1]; line[x * 3 + 2] = mix[2]; } else { line[x * 3 + 0] = 0; line[x * 3 + 1] = 0; line[x * 3 + 2] = 0; } ) } else { REPEAT ( MASK_UPDATE; if (mask & mixmask) { line[x * 3 + 0] = prevline[x * 3 + 0] ^ mix[0]; line[x * 3 + 1] = prevline[x * 3 + 1] ^ mix[1]; line[x * 3 + 2] = prevline[x * 3 + 2] ^ mix[2]; } else { line[x * 3 + 0] = prevline[x * 3 + 0]; line[x * 3 + 1] = prevline[x * 3 + 1]; line[x * 3 + 2] = prevline[x * 3 + 2]; } ) } break; case 3: /* Color */ REPEAT ( line[x * 3 + 0] = color2[0]; line[x * 3 + 1] = color2[1]; line[x * 3 + 2] = color2[2]; ) break; case 4: /* Copy */ REPEAT ( line[x * 3 + 0] = CVAL(input); line[x * 3 + 1] = CVAL(input); line[x * 3 + 2] = CVAL(input); ) break; case 8: /* Bicolor */ REPEAT ( if (bicolor) { line[x * 3 + 0] = color2[0]; line[x * 3 + 1] = color2[1]; line[x * 3 + 2] = color2[2]; bicolor = 0; } else { line[x * 3 + 0] = color1[0]; line[x * 3 + 1] = color1[1]; line[x * 3 + 2] = color1[2]; bicolor = 1; count++; } ) break; case 0xd: /* White */ REPEAT ( line[x * 3 + 0] = 0xff; line[x * 3 + 1] = 0xff; line[x * 3 + 2] = 0xff; ) break; case 0xe: /* Black */ REPEAT ( line[x * 3 + 0] = 0; line[x * 3 + 1] = 0; line[x * 3 + 2] = 0; ) break; default: return 0; break; } } } return 1; } /*****************************************************************************/ /* returns boolean */ int APP_CC rdp_bitmap_decompress(char* output, int width, int height, char* input, int size, int Bpp) { int rv; switch (Bpp) { case 1: rv = bitmap_decompress1(output, width, height, input, size); break; case 2: rv = bitmap_decompress2(output, width, height, input, size); break; case 3: rv = bitmap_decompress3(output, width, height, input, size); break; default: rv = 0; break; } return rv; } xrdp-0.6.0/rdp/rdp_iso.c000066400000000000000000000117631203155130500150650ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2005-2010 librdp iso layer */ #include "rdp.h" /*****************************************************************************/ struct rdp_iso* APP_CC rdp_iso_create(struct rdp_mcs* owner) { struct rdp_iso* self; self = (struct rdp_iso*)g_malloc(sizeof(struct rdp_iso), 1); self->mcs_layer = owner; self->tcp_layer = rdp_tcp_create(self); return self; } /*****************************************************************************/ void APP_CC rdp_iso_delete(struct rdp_iso* self) { if (self == 0) { return; } rdp_tcp_delete(self->tcp_layer); g_free(self); } /*****************************************************************************/ /* returns error */ static int APP_CC rdp_iso_recv_msg(struct rdp_iso* self, struct stream* s, int* code) { int ver; int len; *code = 0; if (rdp_tcp_recv(self->tcp_layer, s, 4) != 0) { DEBUG((" out rdp_iso_recv_msg error rdp_tcp_recv 1 failed")); return 1; } in_uint8(s, ver); if (ver != 3) { DEBUG((" out rdp_iso_recv_msg error ver != 3")); return 1; } in_uint8s(s, 1); in_uint16_be(s, len); if (rdp_tcp_recv(self->tcp_layer, s, len - 4) != 0) { DEBUG((" out rdp_iso_recv_msg error rdp_tcp_recv 2 failed")); return 1; } in_uint8s(s, 1); in_uint8(s, *code); if (*code == ISO_PDU_DT) { in_uint8s(s, 1); } else { in_uint8s(s, 5); } return 0; } /*****************************************************************************/ static int APP_CC rdp_iso_send_msg(struct rdp_iso* self, struct stream* s, int code) { if (rdp_tcp_init(self->tcp_layer, s) != 0) { return 1; } out_uint8(s, 3); out_uint8(s, 0); out_uint16_be(s, 11); /* length */ out_uint8(s, 6); out_uint8(s, code); out_uint16_le(s, 0); out_uint16_le(s, 0); out_uint8(s, 0); s_mark_end(s); if (rdp_tcp_send(self->tcp_layer, s) != 0) { return 1; } return 0; } /*****************************************************************************/ /* returns error */ int APP_CC rdp_iso_recv(struct rdp_iso* self, struct stream* s) { int code; if (rdp_iso_recv_msg(self, s, &code) != 0) { return 1; } if (code != ISO_PDU_DT) { return 1; } return 0; } /*****************************************************************************/ /* returns error */ int APP_CC rdp_iso_init(struct rdp_iso* self, struct stream* s) { rdp_tcp_init(self->tcp_layer, s); s_push_layer(s, iso_hdr, 7); return 0; } /*****************************************************************************/ /* returns error */ int APP_CC rdp_iso_send(struct rdp_iso* self, struct stream* s) { int len; s_pop_layer(s, iso_hdr); len = s->end - s->p; out_uint8(s, 3); out_uint8(s, 0); out_uint16_be(s, len); out_uint8(s, 2); out_uint8(s, ISO_PDU_DT); out_uint8(s, 0x80); if (rdp_tcp_send(self->tcp_layer, s) != 0) { return 1; } return 0; } /*****************************************************************************/ /* returns error */ int APP_CC rdp_iso_connect(struct rdp_iso* self, char* ip, char* port) { int code; struct stream* s; DEBUG((" in rdp_iso_connect")); make_stream(s); init_stream(s, 8192); if (rdp_tcp_connect(self->tcp_layer, ip, port) != 0) { free_stream(s); DEBUG((" out rdp_iso_connect error rdp_tcp_connect failed")); return 1; } if (rdp_iso_send_msg(self, s, ISO_PDU_CR) != 0) { free_stream(s); rdp_tcp_disconnect(self->tcp_layer); DEBUG((" out rdp_iso_connect error rdp_iso_send_msg failed")); return 1; } init_stream(s, 8192); if (rdp_iso_recv_msg(self, s, &code) != 0) { free_stream(s); rdp_tcp_disconnect(self->tcp_layer); DEBUG((" out rdp_iso_connect error rdp_iso_recv_msg failed")); return 1; } if (code != ISO_PDU_CC) { free_stream(s); rdp_tcp_disconnect(self->tcp_layer); DEBUG((" out rdp_iso_connect error code != ISO_PDU_CC")); return 1; } free_stream(s); DEBUG((" out rdp_iso_connect")); return 0; } /*****************************************************************************/ int APP_CC rdp_iso_disconnect(struct rdp_iso* self) { struct stream* s; make_stream(s); init_stream(s, 8192); rdp_iso_send_msg(self, s, ISO_PDU_DR); rdp_tcp_disconnect(self->tcp_layer); free_stream(s); return 0; } xrdp-0.6.0/rdp/rdp_lic.c000066400000000000000000000261051203155130500150360ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2005-2010 licence */ #include "rdp.h" /*****************************************************************************/ struct rdp_lic* APP_CC rdp_lic_create(struct rdp_sec* owner) { struct rdp_lic* self; self = (struct rdp_lic*)g_malloc(sizeof(struct rdp_lic), 1); self->sec_layer = owner; return self; } /*****************************************************************************/ void APP_CC rdp_lic_delete(struct rdp_lic* self) { if (self == 0) { return; } g_free(self); } /*****************************************************************************/ /* Generate a session key and RC4 keys, given client and server randoms */ static void APP_CC rdp_lic_generate_keys(struct rdp_lic* self, char* client_random, char* server_random, char* pre_master_secret) { char master_secret[48]; char key_block[48]; /* Generate master secret and then key material */ rdp_sec_hash_48(master_secret, pre_master_secret, client_random, server_random, 65); rdp_sec_hash_48(key_block, master_secret, server_random, client_random, 65); /* Store first 16 bytes of session key as MAC secret */ g_memcpy(self->licence_sign_key, key_block, 16); /* Generate RC4 key from next 16 bytes */ rdp_sec_hash_16(self->licence_key, key_block + 16, client_random, server_random); } /*****************************************************************************/ static void APP_CC rdp_lic_generate_hwid(struct rdp_lic* self, char* hwid) { rdp_sec_buf_out_uint32(hwid, 2); g_strncpy(hwid + 4, self->sec_layer->rdp_layer->mod->hostname, LICENCE_HWID_SIZE - 4); } /*****************************************************************************/ /* Present an existing licence to the server */ static void APP_CC rdp_lic_present(struct rdp_lic* self, char* client_random, char* rsa_data, char* licence_data, int licence_size, char* hwid, char* signature) { int sec_flags; int length; struct stream* s; sec_flags = SEC_LICENCE_NEG; length = 16 + SEC_RANDOM_SIZE + SEC_MODULUS_SIZE + SEC_PADDING_SIZE + licence_size + LICENCE_HWID_SIZE + LICENCE_SIGNATURE_SIZE; make_stream(s); init_stream(s, 8192); rdp_sec_init(self->sec_layer, s, sec_flags); out_uint8(s, LICENCE_TAG_PRESENT); out_uint8(s, 2); /* version */ out_uint16_le(s, length); out_uint32_le(s, 1); out_uint16_le(s, 0); out_uint16_le(s, 0x0201); out_uint8p(s, client_random, SEC_RANDOM_SIZE); out_uint16_le(s, 0); out_uint16_le(s, (SEC_MODULUS_SIZE + SEC_PADDING_SIZE)); out_uint8p(s, rsa_data, SEC_MODULUS_SIZE); out_uint8s(s, SEC_PADDING_SIZE); out_uint16_le(s, 1); out_uint16_le(s, licence_size); out_uint8p(s, licence_data, licence_size); out_uint16_le(s, 1); out_uint16_le(s, LICENCE_HWID_SIZE); out_uint8p(s, hwid, LICENCE_HWID_SIZE); out_uint8p(s, signature, LICENCE_SIGNATURE_SIZE); s_mark_end(s); rdp_sec_send(self->sec_layer, s, sec_flags); free_stream(s); } /*****************************************************************************/ /* Send a licence request packet */ static void APP_CC rdp_lic_send_request(struct rdp_lic* self, char* client_random, char* rsa_data, char* user, char* host) { int sec_flags; int userlen; int hostlen; int length; struct stream* s; sec_flags = SEC_LICENCE_NEG; userlen = g_strlen(user) + 1; hostlen = g_strlen(host) + 1; length = 128 + userlen + hostlen; make_stream(s); init_stream(s, 8192); rdp_sec_init(self->sec_layer, s, sec_flags); out_uint8(s, LICENCE_TAG_REQUEST); out_uint8(s, 2); /* version */ out_uint16_le(s, length); out_uint32_le(s, 1); out_uint16_le(s, 0); out_uint16_le(s, 0xff01); out_uint8p(s, client_random, SEC_RANDOM_SIZE); out_uint16_le(s, 0); out_uint16_le(s, (SEC_MODULUS_SIZE + SEC_PADDING_SIZE)); out_uint8p(s, rsa_data, SEC_MODULUS_SIZE); out_uint8s(s, SEC_PADDING_SIZE); out_uint16_le(s, LICENCE_TAG_USER); out_uint16_le(s, userlen); out_uint8p(s, user, userlen); out_uint16_le(s, LICENCE_TAG_HOST); out_uint16_le(s, hostlen); out_uint8p(s, host, hostlen); s_mark_end(s); rdp_sec_send(self->sec_layer, s, sec_flags); free_stream(s); } /*****************************************************************************/ /* Process a licence demand packet */ static void APP_CC rdp_lic_process_demand(struct rdp_lic* self, struct stream* s) { char null_data[SEC_MODULUS_SIZE]; char* server_random; char signature[LICENCE_SIGNATURE_SIZE]; char hwid[LICENCE_HWID_SIZE]; char* licence_data; int licence_size; void* crypt_key; licence_data = 0; /* Retrieve the server random from the incoming packet */ in_uint8p(s, server_random, SEC_RANDOM_SIZE); /* We currently use null client keys. This is a bit naughty but, hey, the security of licence negotiation isn't exactly paramount. */ g_memset(null_data, 0, sizeof(null_data)); rdp_lic_generate_keys(self, null_data, server_random, null_data); licence_size = 0; /* todo load_licence(&licence_data); */ if (licence_size > 0) { /* Generate a signature for the HWID buffer */ rdp_lic_generate_hwid(self, hwid); rdp_sec_sign(signature, 16, self->licence_sign_key, 16, hwid, sizeof(hwid)); /* Now encrypt the HWID */ crypt_key = ssl_rc4_info_create(); ssl_rc4_set_key(crypt_key, self->licence_key, 16); ssl_rc4_crypt(crypt_key, hwid, sizeof(hwid)); ssl_rc4_info_delete(crypt_key); rdp_lic_present(self, null_data, null_data, licence_data, licence_size, hwid, signature); g_free(licence_data); return; } rdp_lic_send_request(self, null_data, null_data, self->sec_layer->rdp_layer->mod->username, self->sec_layer->rdp_layer->mod->hostname); } /*****************************************************************************/ /* Send an authentication response packet */ static void APP_CC rdp_lic_send_authresp(struct rdp_lic* self, char* token, char* crypt_hwid, char* signature) { int sec_flags; int length; struct stream* s; sec_flags = SEC_LICENCE_NEG; length = 58; make_stream(s); init_stream(s, 8192); rdp_sec_init(self->sec_layer, s, sec_flags); out_uint8(s, LICENCE_TAG_AUTHRESP); out_uint8(s, 2); /* version */ out_uint16_le(s, length); out_uint16_le(s, 1); out_uint16_le(s, LICENCE_TOKEN_SIZE); out_uint8p(s, token, LICENCE_TOKEN_SIZE); out_uint16_le(s, 1); out_uint16_le(s, LICENCE_HWID_SIZE); out_uint8p(s, crypt_hwid, LICENCE_HWID_SIZE); out_uint8p(s, signature, LICENCE_SIGNATURE_SIZE); s_mark_end(s); rdp_sec_send(self->sec_layer, s, sec_flags); free_stream(s); } /*****************************************************************************/ /* Parse an authentication request packet */ /* returns boolean */ static int APP_CC rdp_lic_parse_authreq(struct rdp_lic* self, struct stream* s, char** token, char** signature) { int tokenlen; in_uint8s(s, 6); /* unknown: f8 3d 15 00 04 f6 */ in_uint16_le(s, tokenlen); if (tokenlen != LICENCE_TOKEN_SIZE) { /* error("token len %d\n", tokenlen); */ return 0; } in_uint8p(s, *token, tokenlen); in_uint8p(s, *signature, LICENCE_SIGNATURE_SIZE); return s_check_end(s); } /*****************************************************************************/ /* Process an authentication request packet */ static void APP_CC rdp_lic_process_authreq(struct rdp_lic* self, struct stream* s) { char* in_token; char* in_sig; char out_token[LICENCE_TOKEN_SIZE]; char decrypt_token[LICENCE_TOKEN_SIZE]; char hwid[LICENCE_HWID_SIZE]; char crypt_hwid[LICENCE_HWID_SIZE]; char sealed_buffer[LICENCE_TOKEN_SIZE + LICENCE_HWID_SIZE]; char out_sig[LICENCE_SIGNATURE_SIZE]; void* crypt_key; in_token = 0; in_sig = 0; /* Parse incoming packet and save the encrypted token */ rdp_lic_parse_authreq(self, s, &in_token, &in_sig); g_memcpy(out_token, in_token, LICENCE_TOKEN_SIZE); /* Decrypt the token. It should read TEST in Unicode. */ crypt_key = ssl_rc4_info_create(); ssl_rc4_set_key(crypt_key, self->licence_key, 16); g_memcpy(decrypt_token, in_token, LICENCE_TOKEN_SIZE); ssl_rc4_crypt(crypt_key, decrypt_token, LICENCE_TOKEN_SIZE); /* Generate a signature for a buffer of token and HWID */ rdp_lic_generate_hwid(self, hwid); g_memcpy(sealed_buffer, decrypt_token, LICENCE_TOKEN_SIZE); g_memcpy(sealed_buffer + LICENCE_TOKEN_SIZE, hwid, LICENCE_HWID_SIZE); rdp_sec_sign(out_sig, 16, self->licence_sign_key, 16, sealed_buffer, sizeof(sealed_buffer)); /* Now encrypt the HWID */ ssl_rc4_set_key(crypt_key, self->licence_key, 16); g_memcpy(crypt_hwid, hwid, LICENCE_HWID_SIZE); ssl_rc4_crypt(crypt_key, crypt_hwid, LICENCE_HWID_SIZE); rdp_lic_send_authresp(self, out_token, crypt_hwid, out_sig); ssl_rc4_info_delete(crypt_key); } /*****************************************************************************/ /* Process an licence issue packet */ static void APP_CC rdp_lic_process_issue(struct rdp_lic* self, struct stream* s) { void* crypt_key; int length; int check; int i; in_uint8s(s, 2); /* 3d 45 - unknown */ in_uint16_le(s, length); if (!s_check_rem(s, length)) { return; } crypt_key = ssl_rc4_info_create(); ssl_rc4_set_key(crypt_key, self->licence_key, 16); ssl_rc4_crypt(crypt_key, s->p, length); ssl_rc4_info_delete(crypt_key); in_uint16_le(s, check); if (check != 0) { return; } self->licence_issued = 1; in_uint8s(s, 2); /* pad */ /* advance to fourth string */ length = 0; for (i = 0; i < 4; i++) { in_uint8s(s, length); in_uint32_le(s, length); if (!s_check_rem(s, length)) { return; } } /* todo save_licence(s->p, length); */ } /******************************************************************************/ /* Process a licence packet */ void APP_CC rdp_lic_process(struct rdp_lic* self, struct stream* s) { int tag; in_uint8(s, tag); in_uint8s(s, 3); /* version, length */ switch (tag) { case LICENCE_TAG_DEMAND: rdp_lic_process_demand(self, s); break; case LICENCE_TAG_AUTHREQ: rdp_lic_process_authreq(self, s); break; case LICENCE_TAG_ISSUE: rdp_lic_process_issue(self, s); break; case LICENCE_TAG_REISSUE: case LICENCE_TAG_RESULT: break; default: break; /* todo unimpl("licence tag 0x%x\n", tag); */ } } xrdp-0.6.0/rdp/rdp_mcs.c000066400000000000000000000310711203155130500150470ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2005-2010 librdp mcs layer */ #include "rdp.h" /*****************************************************************************/ struct rdp_mcs* APP_CC rdp_mcs_create(struct rdp_sec* owner, struct stream* client_mcs_data, struct stream* server_mcs_data) { struct rdp_mcs* self; self = (struct rdp_mcs*)g_malloc(sizeof(struct rdp_mcs), 1); self->sec_layer = owner; self->userid = 1; self->client_mcs_data = client_mcs_data; self->server_mcs_data = server_mcs_data; self->iso_layer = rdp_iso_create(self); return self; } /*****************************************************************************/ void APP_CC rdp_mcs_delete(struct rdp_mcs* self) { if (self == 0) { return; } rdp_iso_delete(self->iso_layer); g_free(self); } /*****************************************************************************/ /* returns error */ int APP_CC rdp_mcs_recv(struct rdp_mcs* self, struct stream* s, int* chan) { int appid; int opcode; int len; DEBUG((" in rdp_mcs_recv")); if (rdp_iso_recv(self->iso_layer, s) != 0) { return 1; } in_uint8(s, opcode); appid = opcode >> 2; if (appid != MCS_SDIN) { DEBUG((" out rdp_mcs_recv error")); return 1; } in_uint8s(s, 2); in_uint16_be(s, *chan); in_uint8s(s, 1); in_uint8(s, len); if (len & 0x80) { in_uint8s(s, 1); } DEBUG((" out rdp_mcs_recv")); return 0; } /*****************************************************************************/ /* returns error */ static int APP_CC rdp_mcs_ber_out_header(struct rdp_mcs* self, struct stream* s, int tag_val, int len) { if (tag_val > 0xff) { out_uint16_be(s, tag_val); } else { out_uint8(s, tag_val); } if (len >= 0x80) { out_uint8(s, 0x82); out_uint16_be(s, len); } else { out_uint8(s, len); } return 0; } #if 0 /*****************************************************************************/ /* returns error */ static int APP_CC rdp_mcs_ber_out_int8(struct rdp_mcs* self, struct stream* s, int value) { rdp_mcs_ber_out_header(self, s, BER_TAG_INTEGER, 1); out_uint8(s, value); return 0; } #endif /*****************************************************************************/ /* returns error */ static int APP_CC rdp_mcs_ber_out_int16(struct rdp_mcs* self, struct stream* s, int value) { rdp_mcs_ber_out_header(self, s, BER_TAG_INTEGER, 2); out_uint8(s, (value >> 8)); out_uint8(s, value); return 0; } #if 0 /*****************************************************************************/ /* returns error */ static int APP_CC rdp_mcs_ber_out_int24(struct rdp_mcs* self, struct stream* s, int value) { rdp_mcs_ber_out_header(self, s, BER_TAG_INTEGER, 3); out_uint8(s, (value >> 16)); out_uint8(s, (value >> 8)); out_uint8(s, value); return 0; } #endif /*****************************************************************************/ /* returns error */ static int APP_CC rdp_mcs_out_domain_params(struct rdp_mcs* self, struct stream* s, int max_channels, int max_users, int max_tokens, int max_pdu_size) { rdp_mcs_ber_out_header(self, s, MCS_TAG_DOMAIN_PARAMS, 32); rdp_mcs_ber_out_int16(self, s, max_channels); rdp_mcs_ber_out_int16(self, s, max_users); rdp_mcs_ber_out_int16(self, s, max_tokens); rdp_mcs_ber_out_int16(self, s, 1); rdp_mcs_ber_out_int16(self, s, 0); rdp_mcs_ber_out_int16(self, s, 1); rdp_mcs_ber_out_int16(self, s, max_pdu_size); rdp_mcs_ber_out_int16(self, s, 2); return 0; } /*****************************************************************************/ /* returns error */ static int APP_CC rdp_mcs_send_connection_initial(struct rdp_mcs* self) { int data_len; int len; struct stream* s; make_stream(s); init_stream(s, 8192); data_len = self->client_mcs_data->end - self->client_mcs_data->data; len = 7 + 3 * 34 + 4 + data_len; if (rdp_iso_init(self->iso_layer, s) != 0) { free_stream(s); return 1; } rdp_mcs_ber_out_header(self, s, MCS_CONNECT_INITIAL, len); rdp_mcs_ber_out_header(self, s, BER_TAG_OCTET_STRING, 0); /* calling domain */ rdp_mcs_ber_out_header(self, s, BER_TAG_OCTET_STRING, 0); /* called domain */ rdp_mcs_ber_out_header(self, s, BER_TAG_BOOLEAN, 1); out_uint8(s, 0xff); /* upward flag */ rdp_mcs_out_domain_params(self, s, 2, 2, 0, 0xffff); /* target params */ rdp_mcs_out_domain_params(self, s, 1, 1, 1, 0x420); /* min params */ rdp_mcs_out_domain_params(self, s, 0xffff, 0xfc17, 0xffff, 0xffff); /* max params */ rdp_mcs_ber_out_header(self, s, BER_TAG_OCTET_STRING, data_len); out_uint8p(s, self->client_mcs_data->data, data_len); s_mark_end(s); if (rdp_iso_send(self->iso_layer, s) != 0) { free_stream(s); return 1; } free_stream(s); return 0; } /*****************************************************************************/ /* returns error */ static int APP_CC rdp_mcs_ber_parse_header(struct rdp_mcs* self, struct stream* s, int tag_val, int* len) { int tag; int l; int i; if (tag_val > 0xff) { in_uint16_be(s, tag); } else { in_uint8(s, tag); } if (tag != tag_val) { return 1; } in_uint8(s, l); if (l & 0x80) { l = l & ~0x80; *len = 0; while (l > 0) { in_uint8(s, i); *len = (*len << 8) | i; l--; } } else { *len = l; } if (s_check(s)) { return 0; } else { return 1; } } /*****************************************************************************/ /* returns error */ static int APP_CC rdp_mcs_parse_domain_params(struct rdp_mcs* self, struct stream* s) { int len; if (rdp_mcs_ber_parse_header(self, s, MCS_TAG_DOMAIN_PARAMS, &len) != 0) { return 1; } in_uint8s(s, len); if (s_check(s)) { return 0; } else { return 1; } } /*****************************************************************************/ /* returns error */ static int APP_CC rdp_mcs_recv_connection_response(struct rdp_mcs* self) { int len; int res; struct stream* s; make_stream(s); init_stream(s, 8192); if (rdp_iso_recv(self->iso_layer, s) != 0) { free_stream(s); return 1; } rdp_mcs_ber_parse_header(self, s, MCS_CONNECT_RESPONSE, &len); rdp_mcs_ber_parse_header(self, s, BER_TAG_RESULT, &len); in_uint8(s, res); if (res != 0) { free_stream(s); return 1; } rdp_mcs_ber_parse_header(self, s, BER_TAG_INTEGER, &len); in_uint8s(s, len); /* connect id */ rdp_mcs_parse_domain_params(self, s); rdp_mcs_ber_parse_header(self, s, BER_TAG_OCTET_STRING, &len); if (len > self->server_mcs_data->size) { len = self->server_mcs_data->size; } in_uint8a(s, self->server_mcs_data->data, len); self->server_mcs_data->p = self->server_mcs_data->data; self->server_mcs_data->end = self->server_mcs_data->data + len; if (s_check_end(s)) { free_stream(s); return 0; } else { free_stream(s); return 1; } } /*****************************************************************************/ /* returns error */ static int APP_CC rdp_mcs_send_edrq(struct rdp_mcs* self) { struct stream* s; make_stream(s); init_stream(s, 8192); if (rdp_iso_init(self->iso_layer, s) != 0) { free_stream(s); return 1; } out_uint8(s, (MCS_EDRQ << 2)); out_uint16_be(s, 0x100); /* height */ out_uint16_be(s, 0x100); /* interval */ s_mark_end(s); if (rdp_iso_send(self->iso_layer, s) != 0) { free_stream(s); return 1; } free_stream(s); return 0; } /*****************************************************************************/ /* returns error */ static int APP_CC rdp_mcs_send_aurq(struct rdp_mcs* self) { struct stream* s; make_stream(s); init_stream(s, 8192); if (rdp_iso_init(self->iso_layer, s) != 0) { free_stream(s); return 1; } out_uint8(s, (MCS_AURQ << 2)); s_mark_end(s); if (rdp_iso_send(self->iso_layer, s) != 0) { free_stream(s); return 1; } free_stream(s); return 0; } /*****************************************************************************/ /* returns error */ static int APP_CC rdp_mcs_recv_aucf(struct rdp_mcs* self) { int opcode; int res; struct stream* s; make_stream(s); init_stream(s, 8192); if (rdp_iso_recv(self->iso_layer, s) != 0) { free_stream(s); return 1; } in_uint8(s, opcode); if ((opcode >> 2) != MCS_AUCF) { free_stream(s); return 1; } in_uint8(s, res); if (res != 0) { free_stream(s); return 1; } if (opcode & 2) { in_uint16_be(s, self->userid); } if (!(s_check_end(s))) { free_stream(s); return 1; } free_stream(s); return 0; } /*****************************************************************************/ /* returns error */ static int APP_CC rdp_mcs_send_cjrq(struct rdp_mcs* self, int chanid) { struct stream* s; make_stream(s); init_stream(s, 8192); if (rdp_iso_init(self->iso_layer, s) != 0) { free_stream(s); return 1; } out_uint8(s, (MCS_CJRQ << 2)); out_uint16_be(s, self->userid); out_uint16_be(s, chanid); s_mark_end(s); if (rdp_iso_send(self->iso_layer, s) != 0) { free_stream(s); return 1; } free_stream(s); return 0; } /*****************************************************************************/ /* returns error */ static int APP_CC rdp_mcs_recv_cjcf(struct rdp_mcs* self) { int opcode; int res; struct stream* s; make_stream(s); init_stream(s, 8192); if (rdp_iso_recv(self->iso_layer, s) != 0) { free_stream(s); return 1; } in_uint8(s, opcode); if ((opcode >> 2) != MCS_CJCF) { free_stream(s); return 1; } in_uint8(s, res); if (res != 0) { free_stream(s); return 1; } in_uint8s(s, 4); /* mcs_userid, req_chanid */ if (opcode & 2) { in_uint8s(s, 2); /* join_chanid */ } if (!(s_check_end(s))) { free_stream(s); return 1; } free_stream(s); return 0; } /*****************************************************************************/ /* returns error */ int APP_CC rdp_mcs_connect(struct rdp_mcs* self, char* ip, char* port) { DEBUG((" in rdp_mcs_connect")); if (rdp_iso_connect(self->iso_layer, ip, port) != 0) { DEBUG((" out rdp_mcs_connect error rdp_iso_connect failed")); return 1; } rdp_mcs_send_connection_initial(self); if (rdp_mcs_recv_connection_response(self) != 0) { rdp_iso_disconnect(self->iso_layer); DEBUG((" out rdp_mcs_connect error rdp_mcs_recv_connection_response \ failed")); return 1; } rdp_mcs_send_edrq(self); rdp_mcs_send_aurq(self); if (rdp_mcs_recv_aucf(self) != 0) { rdp_iso_disconnect(self->iso_layer); DEBUG((" out rdp_mcs_connect error rdp_mcs_recv_aucf failed")); return 1; } rdp_mcs_send_cjrq(self, self->userid + 1001); if (rdp_mcs_recv_cjcf(self) != 0) { rdp_iso_disconnect(self->iso_layer); DEBUG((" out rdp_mcs_connect error rdp_mcs_recv_cjcf 1 failed")); return 1; } rdp_mcs_send_cjrq(self, MCS_GLOBAL_CHANNEL); if (rdp_mcs_recv_cjcf(self) != 0) { rdp_iso_disconnect(self->iso_layer); DEBUG((" out rdp_mcs_connect error rdp_mcs_recv_cjcf 2 failed")); return 1; } DEBUG((" out rdp_mcs_connect")); return 0; } /*****************************************************************************/ /* returns error */ int APP_CC rdp_mcs_init(struct rdp_mcs* self, struct stream* s) { rdp_iso_init(self->iso_layer, s); s_push_layer(s, mcs_hdr, 8); return 0; } /*****************************************************************************/ /* returns error */ int APP_CC rdp_mcs_send(struct rdp_mcs* self, struct stream* s) { int len; s_pop_layer(s, mcs_hdr); len = (s->end - s->p) - 8; len = len | 0x8000; out_uint8(s, MCS_SDRQ << 2); out_uint16_be(s, self->userid); out_uint16_be(s, MCS_GLOBAL_CHANNEL); out_uint8(s, 0x70); out_uint16_be(s, len); if (rdp_iso_send(self->iso_layer, s) != 0) { return 1; } return 0; } xrdp-0.6.0/rdp/rdp_orders.c000066400000000000000000001277011203155130500155710ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2005-2010 librdp orders */ #include "rdp.h" #ifndef NULL #define NULL 0 #endif /*****************************************************************************/ struct rdp_orders* APP_CC rdp_orders_create(struct rdp_rdp* owner) { struct rdp_orders* self = (struct rdp_orders *)NULL; self = (struct rdp_orders*)g_malloc(sizeof(struct rdp_orders), 1); self->rdp_layer = owner; return self; } /*****************************************************************************/ void APP_CC rdp_orders_delete(struct rdp_orders* self) { int i = 0; int j = 0; if (self == 0) { return; } /* free the colormap cache */ for (i = 0; i < 6; i++) { g_free(self->cache_colormap[i]); } /* free the bitmap cache */ for (i = 0; i < 3; i++) { for (j = 0; j < 600; j++) { if (self->cache_bitmap[i][j] != 0) { g_free(self->cache_bitmap[i][j]->data); } g_free(self->cache_bitmap[i][j]); } } g_free(self); } /*****************************************************************************/ void APP_CC rdp_orders_reset_state(struct rdp_orders* self) { g_memset(&self->state, 0, sizeof(self->state)); } /*****************************************************************************/ /* Read field indicating which parameters are present */ static void APP_CC rdp_orders_in_present(struct stream* s, int* present, int flags, int size) { int bits = 0; int i = 0; if (flags & RDP_ORDER_SMALL) { size--; } if (flags & RDP_ORDER_TINY) { if (size < 2) { size = 0; } else { size -= 2; } } *present = 0; for (i = 0; i < size; i++) { in_uint8(s, bits); *present |= bits << (i * 8); } } /*****************************************************************************/ /* Read a co-ordinate (16-bit, or 8-bit delta) */ static void APP_CC rdp_orders_in_coord(struct stream* s, int* coord, int delta) { int change = 0; if (delta) { in_sint8(s, change); *coord += change; } else { in_sint16_le(s, *coord); } } /*****************************************************************************/ /* Parse bounds information */ static void APP_CC rdp_orders_parse_bounds(struct rdp_orders* self, struct stream* s) { int present = 0; in_uint8(s, present); if (present & 1) { rdp_orders_in_coord(s, &self->state.clip_left, 0); } else if (present & 16) { rdp_orders_in_coord(s, &self->state.clip_left, 1); } if (present & 2) { rdp_orders_in_coord(s, &self->state.clip_top, 0); } else if (present & 32) { rdp_orders_in_coord(s, &self->state.clip_top, 1); } if (present & 4) { rdp_orders_in_coord(s, &self->state.clip_right, 0); } else if (present & 64) { rdp_orders_in_coord(s, &self->state.clip_right, 1); } if (present & 8) { rdp_orders_in_coord(s, &self->state.clip_bottom, 0); } else if (present & 128) { rdp_orders_in_coord(s, &self->state.clip_bottom, 1); } } /*****************************************************************************/ /* Process a colormap cache order */ static void APP_CC rdp_orders_process_colcache(struct rdp_orders* self, struct stream* s, int flags) { struct rdp_colormap* colormap = (struct rdp_colormap *)NULL; struct stream* rec_s = (struct stream *)NULL; int cache_id = 0; int i = 0; colormap = (struct rdp_colormap*)g_malloc(sizeof(struct rdp_colormap), 1); in_uint8(s, cache_id); in_uint16_le(s, colormap->ncolors); for (i = 0; i < colormap->ncolors; i++) { in_uint32_le(s, colormap->colors[i]); } g_free(self->cache_colormap[cache_id]); self->cache_colormap[cache_id] = colormap; if (self->rdp_layer->rec_mode) { rdp_rec_check_file(self->rdp_layer); make_stream(rec_s); init_stream(rec_s, 4096); s_push_layer(rec_s, iso_hdr, 4); out_uint8(rec_s, 10); out_uint8(rec_s, cache_id); for (i = 0; i < 256; i++) { out_uint32_le(rec_s, colormap->colors[i]); } rdp_rec_write_item(self->rdp_layer, rec_s); free_stream(rec_s); } } /*****************************************************************************/ /* Process a raw bitmap cache order */ static void APP_CC rdp_orders_process_raw_bmpcache(struct rdp_orders* self, struct stream* s, int flags) { int cache_idx = 0; int bufsize = 0; int cache_id = 0; int width = 0; int height = 0; int bpp = 0; int Bpp = 0; int x = 0; int y = 0; char* inverted = (char *)NULL; char* dst = (char *)NULL; struct rdp_bitmap* bitmap = (struct rdp_bitmap *)NULL; struct stream* rec_s = (struct stream *)NULL; in_uint8(s, cache_id); in_uint8s(s, 1); in_uint8(s, width); in_uint8(s, height); in_uint8(s, bpp); Bpp = (bpp + 7) / 8; in_uint16_le(s, bufsize); in_uint16_le(s, cache_idx); inverted = (char*)g_malloc(width * height * Bpp, 0); for (y = 0; y < height; y++) { dst = inverted + (((height - y) - 1) * (width * Bpp)); if (Bpp == 1) { for (x = 0; x < width; x++) { in_uint8(s, dst[x]); } } else if (Bpp == 2) { for (x = 0; x < width; x++) { in_uint16_le(s, ((tui16*)dst)[x]); } } else if (Bpp == 3) { for (x = 0; x < width; x++) { in_uint8(s, dst[x * 3 + 0]); in_uint8(s, dst[x * 3 + 1]); in_uint8(s, dst[x * 3 + 2]); } } } bitmap = (struct rdp_bitmap*)g_malloc(sizeof(struct rdp_bitmap), 0); bitmap->width = width; bitmap->height = height; bitmap->bpp = bpp; bitmap->data = inverted; if (self->cache_bitmap[cache_id][cache_idx] != 0) { g_free(self->cache_bitmap[cache_id][cache_idx]->data); } g_free(self->cache_bitmap[cache_id][cache_idx]); self->cache_bitmap[cache_id][cache_idx] = bitmap; if (self->rdp_layer->rec_mode) { y = width * height * Bpp; rdp_rec_check_file(self->rdp_layer); make_stream(rec_s); init_stream(rec_s, y + 256); s_push_layer(rec_s, iso_hdr, 4); out_uint8(rec_s, 8); out_uint8(rec_s, cache_id); out_uint16_le(rec_s, cache_idx); out_uint16_le(rec_s, width); out_uint16_le(rec_s, height); out_uint16_le(rec_s, y); out_uint8a(rec_s, inverted, y); rdp_rec_write_item(self->rdp_layer, rec_s); free_stream(rec_s); } } /*****************************************************************************/ /* Process a bitmap cache order */ static void APP_CC rdp_orders_process_bmpcache(struct rdp_orders* self, struct stream* s, int flags) { char* data = (char *)NULL; char* bmpdata = (char *)NULL; int cache_idx = 0; int size = 0; int cache_id = 0; int width = 0; int height = 0; int bpp = 0; int Bpp = 0; int bufsize = 0; int pad1 = 0; int pad2 = 0; int row_size = 0; int final_size = 0; struct rdp_bitmap* bitmap = (struct rdp_bitmap *)NULL; struct stream* rec_s = (struct stream *)NULL; in_uint8(s, cache_id); in_uint8(s, pad1); in_uint8(s, width); in_uint8(s, height); in_uint8(s, bpp); Bpp = (bpp + 7) / 8; in_uint16_le(s, bufsize); in_uint16_le(s, cache_idx); if (flags & 1024) { size = bufsize; } else { in_uint16_le(s, pad2); in_uint16_le(s, size); in_uint16_le(s, row_size); in_uint16_le(s, final_size); } in_uint8p(s, data, size); bmpdata = (char*)g_malloc(width * height * Bpp, 0); if (rdp_bitmap_decompress(bmpdata, width, height, data, size, Bpp)) { } else { /* error */ } bitmap = (struct rdp_bitmap*)g_malloc(sizeof(struct rdp_bitmap), 0); bitmap->width = width; bitmap->height = height; bitmap->bpp = bpp; bitmap->data = bmpdata; if (self->cache_bitmap[cache_id][cache_idx] != 0) { g_free(self->cache_bitmap[cache_id][cache_idx]->data); } g_free(self->cache_bitmap[cache_id][cache_idx]); self->cache_bitmap[cache_id][cache_idx] = bitmap; if (self->rdp_layer->rec_mode) { size = width * height * Bpp; rdp_rec_check_file(self->rdp_layer); make_stream(rec_s); init_stream(rec_s, size + 256); s_push_layer(rec_s, iso_hdr, 4); out_uint8(rec_s, 8); out_uint8(rec_s, cache_id); out_uint16_le(rec_s, cache_idx); out_uint16_le(rec_s, width); out_uint16_le(rec_s, height); out_uint16_le(rec_s, size); out_uint8a(rec_s, bmpdata, size); rdp_rec_write_item(self->rdp_layer, rec_s); free_stream(rec_s); } } /*****************************************************************************/ /* Process a font cache order */ static void APP_CC rdp_orders_process_fontcache(struct rdp_orders* self, struct stream* s, int flags) { struct stream* rec_s = (struct stream *)NULL; int font = 0; int nglyphs = 0; int character = 0; int offset = 0; int baseline = 0; int width = 0; int height = 0; int i = 0; int datasize = 0; char* data = (char *)NULL; in_uint8(s, font); in_uint8(s, nglyphs); for (i = 0; i < nglyphs; i++) { in_uint16_le(s, character); in_uint16_le(s, offset); in_uint16_le(s, baseline); in_uint16_le(s, width); in_uint16_le(s, height); datasize = (height * ((width + 7) / 8) + 3) & ~3; in_uint8p(s, data, datasize); self->rdp_layer->mod->server_add_char(self->rdp_layer->mod, font, character, offset, baseline, width, height, data); if (self->rdp_layer->rec_mode) { rdp_rec_check_file(self->rdp_layer); make_stream(rec_s); init_stream(rec_s, datasize + 256); s_push_layer(rec_s, iso_hdr, 4); out_uint8(rec_s, 9); out_uint8(rec_s, font); out_uint16_le(rec_s, character); out_uint16_le(rec_s, offset); out_uint16_le(rec_s, baseline); out_uint16_le(rec_s, width); out_uint16_le(rec_s, height); out_uint16_le(rec_s, datasize); out_uint8a(rec_s, data, datasize); rdp_rec_write_item(self->rdp_layer, rec_s); free_stream(rec_s); } } } /*****************************************************************************/ /* Process a secondary order */ static int APP_CC rdp_orders_process_secondary_order(struct rdp_orders* self, struct stream* s) { short length = 0; int flags = 0; int type = 0; char* next_order = (char *)NULL; in_uint16_le(s, length); in_uint16_le(s, flags); in_uint8(s, type); next_order = s->p + length + 7; switch (type) { case RDP_ORDER_COLCACHE: rdp_orders_process_colcache(self, s, flags); break; case RDP_ORDER_RAW_BMPCACHE: rdp_orders_process_raw_bmpcache(self, s, flags); break; case RDP_ORDER_BMPCACHE: rdp_orders_process_bmpcache(self, s, flags); break; case RDP_ORDER_FONTCACHE: rdp_orders_process_fontcache(self, s, flags); break; default: /* error, unknown order */ break; } s->p = next_order; return 0; } /*****************************************************************************/ /* Read a color entry */ static void APP_CC rdp_orders_in_color(struct stream* s, int* color) { int i = 0; in_uint8(s, i); *color = i; in_uint8(s, i); *color |= i << 8; in_uint8(s, i); *color |= i << 16; } /*****************************************************************************/ /* Parse a brush */ static void APP_CC rdp_orders_parse_brush(struct stream* s, struct rdp_brush* brush, int present) { if (present & 1) { in_uint8(s, brush->xorigin); } if (present & 2) { in_uint8(s, brush->yorigin); } if (present & 4) { in_uint8(s, brush->style); } if (present & 8) { in_uint8(s, brush->pattern[0]); } if (present & 16) { in_uint8a(s, brush->pattern + 1, 7); } } /*****************************************************************************/ /* Parse a pen */ static void APP_CC rdp_orders_parse_pen(struct stream* s, struct rdp_pen* pen, int present) { if (present & 1) { in_uint8(s, pen->style); } if (present & 2) { in_uint8(s, pen->width); } if (present & 4) { rdp_orders_in_color(s, &pen->color); } } /*****************************************************************************/ /* Process a text order */ static void APP_CC rdp_orders_process_text2(struct rdp_orders* self, struct stream* s, int present, int delta) { int fgcolor = 0; int bgcolor = 0; struct stream* rec_s = (struct stream *)NULL; if (present & 0x000001) { in_uint8(s, self->state.text_font); } if (present & 0x000002) { in_uint8(s, self->state.text_flags); } if (present & 0x000004) { in_uint8(s, self->state.text_opcode); } if (present & 0x000008) { in_uint8(s, self->state.text_mixmode); } if (present & 0x000010) { rdp_orders_in_color(s, &self->state.text_fgcolor); } if (present & 0x000020) { rdp_orders_in_color(s, &self->state.text_bgcolor); } if (present & 0x000040) { in_sint16_le(s, self->state.text_clipleft); } if (present & 0x000080) { in_sint16_le(s, self->state.text_cliptop); } if (present & 0x000100) { in_sint16_le(s, self->state.text_clipright); } if (present & 0x000200) { in_sint16_le(s, self->state.text_clipbottom); } if (present & 0x000400) { in_sint16_le(s, self->state.text_boxleft); } if (present & 0x000800) { in_sint16_le(s, self->state.text_boxtop); } if (present & 0x001000) { in_sint16_le(s, self->state.text_boxright); } if (present & 0x002000) { in_sint16_le(s, self->state.text_boxbottom); } rdp_orders_parse_brush(s, &self->state.text_brush, present >> 14); if (present & 0x080000) { in_sint16_le(s, self->state.text_x); } if (present & 0x100000) { in_sint16_le(s, self->state.text_y); } if (present & 0x200000) { in_uint8(s, self->state.text_length); in_uint8a(s, self->state.text_text, self->state.text_length); } self->rdp_layer->mod->server_set_opcode(self->rdp_layer->mod, self->state.text_opcode); fgcolor = rdp_orders_convert_color(self->rdp_layer->mod->rdp_bpp, self->rdp_layer->mod->xrdp_bpp, self->state.text_fgcolor, self->rdp_layer->colormap.colors); self->rdp_layer->mod->server_set_fgcolor(self->rdp_layer->mod, fgcolor); bgcolor = rdp_orders_convert_color(self->rdp_layer->mod->rdp_bpp, self->rdp_layer->mod->xrdp_bpp, self->state.text_bgcolor, self->rdp_layer->colormap.colors); self->rdp_layer->mod->server_set_bgcolor(self->rdp_layer->mod, bgcolor); self->rdp_layer->mod->server_draw_text(self->rdp_layer->mod, self->state.text_font, self->state.text_flags, self->state.text_mixmode, self->state.text_clipleft, self->state.text_cliptop, self->state.text_clipright, self->state.text_clipbottom, self->state.text_boxleft, self->state.text_boxtop, self->state.text_boxright, self->state.text_boxbottom, self->state.text_x, self->state.text_y, self->state.text_text, self->state.text_length); self->rdp_layer->mod->server_set_opcode(self->rdp_layer->mod, 0xcc); if (self->rdp_layer->rec_mode) { rdp_rec_check_file(self->rdp_layer); make_stream(rec_s); init_stream(rec_s, 512); s_push_layer(rec_s, iso_hdr, 4); out_uint8(rec_s, 7); out_uint8(rec_s, self->state.text_font); out_uint8(rec_s, self->state.text_flags); out_uint8(rec_s, self->state.text_opcode); out_uint8(rec_s, self->state.text_mixmode); out_uint32_le(rec_s, self->state.text_fgcolor); out_uint32_le(rec_s, self->state.text_bgcolor); out_uint16_le(rec_s, self->state.text_clipleft); out_uint16_le(rec_s, self->state.text_cliptop); out_uint16_le(rec_s, self->state.text_clipright); out_uint16_le(rec_s, self->state.text_clipbottom); out_uint16_le(rec_s, self->state.text_boxleft); out_uint16_le(rec_s, self->state.text_boxtop); out_uint16_le(rec_s, self->state.text_boxright); out_uint16_le(rec_s, self->state.text_boxbottom); out_uint16_le(rec_s, self->state.text_x); out_uint16_le(rec_s, self->state.text_y); out_uint16_le(rec_s, self->state.text_length); out_uint8a(rec_s, self->state.text_text, self->state.text_length); rdp_rec_write_item(self->rdp_layer, rec_s); free_stream(rec_s); } } /*****************************************************************************/ /* Process a destination blt order */ static void APP_CC rdp_orders_process_destblt(struct rdp_orders* self, struct stream* s, int present, int delta) { struct stream* rec_s = (struct stream *)NULL; if (present & 0x01) { rdp_orders_in_coord(s, &self->state.dest_x, delta); } if (present & 0x02) { rdp_orders_in_coord(s, &self->state.dest_y, delta); } if (present & 0x04) { rdp_orders_in_coord(s, &self->state.dest_cx, delta); } if (present & 0x08) { rdp_orders_in_coord(s, &self->state.dest_cy, delta); } if (present & 0x10) { in_uint8(s, self->state.dest_opcode); } self->rdp_layer->mod->server_set_opcode(self->rdp_layer->mod, self->state.dest_opcode); self->rdp_layer->mod->server_fill_rect(self->rdp_layer->mod, self->state.dest_x, self->state.dest_y, self->state.dest_cx, self->state.dest_cy); self->rdp_layer->mod->server_set_opcode(self->rdp_layer->mod, 0xcc); if (self->rdp_layer->rec_mode) { rdp_rec_check_file(self->rdp_layer); make_stream(rec_s); init_stream(rec_s, 512); s_push_layer(rec_s, iso_hdr, 4); out_uint8(rec_s, 6); out_uint16_le(rec_s, self->state.dest_x); out_uint16_le(rec_s, self->state.dest_y); out_uint16_le(rec_s, self->state.dest_cx); out_uint16_le(rec_s, self->state.dest_cy); out_uint8(rec_s, self->state.dest_opcode); rdp_rec_write_item(self->rdp_layer, rec_s); free_stream(rec_s); } } /*****************************************************************************/ /* Process a pattern blt order */ static void APP_CC rdp_orders_process_patblt(struct rdp_orders* self, struct stream* s, int present, int delta) { int fgcolor = 0; int bgcolor = 0; struct stream* rec_s = (struct stream *)NULL; if (present & 0x0001) { rdp_orders_in_coord(s, &self->state.pat_x, delta); } if (present & 0x0002) { rdp_orders_in_coord(s, &self->state.pat_y, delta); } if (present & 0x0004) { rdp_orders_in_coord(s, &self->state.pat_cx, delta); } if (present & 0x0008) { rdp_orders_in_coord(s, &self->state.pat_cy, delta); } if (present & 0x0010) { in_uint8(s, self->state.pat_opcode); } if (present & 0x0020) { rdp_orders_in_color(s, &self->state.pat_bgcolor); } if (present & 0x0040) { rdp_orders_in_color(s, &self->state.pat_fgcolor); } rdp_orders_parse_brush(s, &self->state.pat_brush, present >> 7); self->rdp_layer->mod->server_set_opcode(self->rdp_layer->mod, self->state.pat_opcode); self->rdp_layer->mod->server_set_mixmode(self->rdp_layer->mod, 1); fgcolor = rdp_orders_convert_color(self->rdp_layer->mod->rdp_bpp, self->rdp_layer->mod->xrdp_bpp, self->state.pat_fgcolor, self->rdp_layer->colormap.colors); self->rdp_layer->mod->server_set_fgcolor(self->rdp_layer->mod, fgcolor); bgcolor = rdp_orders_convert_color(self->rdp_layer->mod->rdp_bpp, self->rdp_layer->mod->xrdp_bpp, self->state.pat_bgcolor, self->rdp_layer->colormap.colors); self->rdp_layer->mod->server_set_bgcolor(self->rdp_layer->mod, bgcolor); self->rdp_layer->mod->server_set_brush(self->rdp_layer->mod, self->state.pat_brush.xorigin, self->state.pat_brush.yorigin, self->state.pat_brush.style, self->state.pat_brush.pattern); self->rdp_layer->mod->server_fill_rect(self->rdp_layer->mod, self->state.pat_x, self->state.pat_y, self->state.pat_cx, self->state.pat_cy); self->rdp_layer->mod->server_set_opcode(self->rdp_layer->mod, 0xcc); self->rdp_layer->mod->server_set_mixmode(self->rdp_layer->mod, 0); if (self->rdp_layer->rec_mode) { rdp_rec_check_file(self->rdp_layer); make_stream(rec_s); init_stream(rec_s, 512); s_push_layer(rec_s, iso_hdr, 4); out_uint8(rec_s, 5); out_uint16_le(rec_s, self->state.pat_x); out_uint16_le(rec_s, self->state.pat_y); out_uint16_le(rec_s, self->state.pat_cx); out_uint16_le(rec_s, self->state.pat_cy); out_uint8(rec_s, self->state.pat_opcode); out_uint32_le(rec_s, self->state.pat_fgcolor); out_uint32_le(rec_s, self->state.pat_bgcolor); out_uint8(rec_s, self->state.pat_brush.xorigin); out_uint8(rec_s, self->state.pat_brush.yorigin); out_uint8(rec_s, self->state.pat_brush.style); out_uint8a(rec_s, self->state.pat_brush.pattern, 8); rdp_rec_write_item(self->rdp_layer, rec_s); free_stream(rec_s); } } /*****************************************************************************/ /* Process a screen blt order */ static void APP_CC rdp_orders_process_screenblt(struct rdp_orders* self, struct stream* s, int present, int delta) { struct stream* rec_s; if (present & 0x0001) { rdp_orders_in_coord(s, &self->state.screenblt_x, delta); } if (present & 0x0002) { rdp_orders_in_coord(s, &self->state.screenblt_y, delta); } if (present & 0x0004) { rdp_orders_in_coord(s, &self->state.screenblt_cx, delta); } if (present & 0x0008) { rdp_orders_in_coord(s, &self->state.screenblt_cy, delta); } if (present & 0x0010) { in_uint8(s, self->state.screenblt_opcode); } if (present & 0x0020) { rdp_orders_in_coord(s, &self->state.screenblt_srcx, delta); } if (present & 0x0040) { rdp_orders_in_coord(s, &self->state.screenblt_srcy, delta); } self->rdp_layer->mod->server_set_opcode(self->rdp_layer->mod, self->state.screenblt_opcode); self->rdp_layer->mod->server_screen_blt(self->rdp_layer->mod, self->state.screenblt_x, self->state.screenblt_y, self->state.screenblt_cx, self->state.screenblt_cy, self->state.screenblt_srcx, self->state.screenblt_srcy); self->rdp_layer->mod->server_set_opcode(self->rdp_layer->mod, 0xcc); if (self->rdp_layer->rec_mode) { rdp_rec_check_file(self->rdp_layer); make_stream(rec_s); init_stream(rec_s, 512); s_push_layer(rec_s, iso_hdr, 4); out_uint8(rec_s, 4); out_uint16_le(rec_s, self->state.screenblt_x); out_uint16_le(rec_s, self->state.screenblt_y); out_uint16_le(rec_s, self->state.screenblt_cx); out_uint16_le(rec_s, self->state.screenblt_cy); out_uint16_le(rec_s, self->state.screenblt_srcx); out_uint16_le(rec_s, self->state.screenblt_srcy); out_uint8(rec_s, self->state.screenblt_opcode); rdp_rec_write_item(self->rdp_layer, rec_s); free_stream(rec_s); } } /*****************************************************************************/ /* Process a line order */ static void APP_CC rdp_orders_process_line(struct rdp_orders* self, struct stream* s, int present, int delta) { int bgcolor = 0; int fgcolor = 0; struct stream* rec_s = (struct stream *)NULL; if (present & 0x0001) { in_uint16_le(s, self->state.line_mixmode); } if (present & 0x0002) { rdp_orders_in_coord(s, &self->state.line_startx, delta); } if (present & 0x0004) { rdp_orders_in_coord(s, &self->state.line_starty, delta); } if (present & 0x0008) { rdp_orders_in_coord(s, &self->state.line_endx, delta); } if (present & 0x0010) { rdp_orders_in_coord(s, &self->state.line_endy, delta); } if (present & 0x0020) { rdp_orders_in_color(s, &self->state.line_bgcolor); } if (present & 0x0040) { in_uint8(s, self->state.line_opcode); } rdp_orders_parse_pen(s, &self->state.line_pen, present >> 7); self->rdp_layer->mod->server_set_opcode(self->rdp_layer->mod, self->state.line_opcode); bgcolor = rdp_orders_convert_color(self->rdp_layer->mod->rdp_bpp, self->rdp_layer->mod->xrdp_bpp, self->state.line_bgcolor, self->rdp_layer->colormap.colors); fgcolor = rdp_orders_convert_color(self->rdp_layer->mod->rdp_bpp, self->rdp_layer->mod->xrdp_bpp, self->state.line_pen.color, self->rdp_layer->colormap.colors); self->rdp_layer->mod->server_set_fgcolor(self->rdp_layer->mod, fgcolor); self->rdp_layer->mod->server_set_bgcolor(self->rdp_layer->mod, bgcolor); self->rdp_layer->mod->server_set_pen(self->rdp_layer->mod, self->state.line_pen.style, self->state.line_pen.width); self->rdp_layer->mod->server_draw_line(self->rdp_layer->mod, self->state.line_startx, self->state.line_starty, self->state.line_endx, self->state.line_endy); self->rdp_layer->mod->server_set_opcode(self->rdp_layer->mod, 0xcc); if (self->rdp_layer->rec_mode) { rdp_rec_check_file(self->rdp_layer); make_stream(rec_s); init_stream(rec_s, 512); s_push_layer(rec_s, iso_hdr, 4); out_uint8(rec_s, 3); out_uint16_le(rec_s, self->state.line_mixmode); out_uint16_le(rec_s, self->state.line_startx); out_uint16_le(rec_s, self->state.line_starty); out_uint16_le(rec_s, self->state.line_endx); out_uint16_le(rec_s, self->state.line_endy); out_uint32_le(rec_s, self->state.line_bgcolor); out_uint8(rec_s, self->state.line_opcode); out_uint8(rec_s, self->state.line_pen.style); out_uint8(rec_s, self->state.line_pen.width); out_uint32_le(rec_s, self->state.line_pen.color); rdp_rec_write_item(self->rdp_layer, rec_s); free_stream(rec_s); } } /*****************************************************************************/ /* Process an opaque rectangle order */ static void APP_CC rdp_orders_process_rect(struct rdp_orders* self, struct stream* s, int present, int delta) { int i = 0; int fgcolor = 0; struct stream* rec_s = (struct stream *)NULL; if (present & 0x01) { rdp_orders_in_coord(s, &self->state.rect_x, delta); } if (present & 0x02) { rdp_orders_in_coord(s, &self->state.rect_y, delta); } if (present & 0x04) { rdp_orders_in_coord(s, &self->state.rect_cx, delta); } if (present & 0x08) { rdp_orders_in_coord(s, &self->state.rect_cy, delta); } if (present & 0x10) { in_uint8(s, i); self->state.rect_color = (self->state.rect_color & 0xffffff00) | i; } if (present & 0x20) { in_uint8(s, i); self->state.rect_color = (self->state.rect_color & 0xffff00ff) | (i << 8); } if (present & 0x40) { in_uint8(s, i); self->state.rect_color = (self->state.rect_color & 0xff00ffff) | (i << 16); } fgcolor = rdp_orders_convert_color(self->rdp_layer->mod->rdp_bpp, self->rdp_layer->mod->xrdp_bpp, self->state.rect_color, self->rdp_layer->colormap.colors); self->rdp_layer->mod->server_set_fgcolor(self->rdp_layer->mod, fgcolor); self->rdp_layer->mod->server_fill_rect(self->rdp_layer->mod, self->state.rect_x, self->state.rect_y, self->state.rect_cx, self->state.rect_cy); if (self->rdp_layer->rec_mode) { rdp_rec_check_file(self->rdp_layer); make_stream(rec_s); init_stream(rec_s, 512); s_push_layer(rec_s, iso_hdr, 4); out_uint8(rec_s, 1); out_uint16_le(rec_s, self->state.rect_x); out_uint16_le(rec_s, self->state.rect_y); out_uint16_le(rec_s, self->state.rect_cx); out_uint16_le(rec_s, self->state.rect_cy); out_uint32_le(rec_s, self->state.rect_color); rdp_rec_write_item(self->rdp_layer, rec_s); free_stream(rec_s); } } /*****************************************************************************/ /* Process a desktop save order */ static void APP_CC rdp_orders_process_desksave(struct rdp_orders* self, struct stream* s, int present, int delta) { int width = 0; int height = 0; if (present & 0x01) { in_uint32_le(s, self->state.desksave_offset); } if (present & 0x02) { rdp_orders_in_coord(s, &self->state.desksave_left, delta); } if (present & 0x04) { rdp_orders_in_coord(s, &self->state.desksave_top, delta); } if (present & 0x08) { rdp_orders_in_coord(s, &self->state.desksave_right, delta); } if (present & 0x10) { rdp_orders_in_coord(s, &self->state.desksave_bottom, delta); } if (present & 0x20) { in_uint8(s, self->state.desksave_action); } // width = (self->state.desksave_right - self->state.desksave_left) + 1; // height = (self->state.desksave_bottom - self->state.desksave_top) + 1; if (self->state.desksave_action == 0) { // ui_desktop_save(os->offset, os->left, os->top, width, height); } else { // ui_desktop_restore(os->offset, os->left, os->top, width, height); } } /*****************************************************************************/ /* Process a memory blt order */ static void APP_CC rdp_orders_process_memblt(struct rdp_orders* self, struct stream* s, int present, int delta) { struct rdp_bitmap* bitmap = (struct rdp_bitmap *)NULL; struct stream* rec_s = (struct stream *)NULL; char* bmpdata = (char *)NULL; if (present & 0x0001) { in_uint8(s, self->state.memblt_cache_id); in_uint8(s, self->state.memblt_color_table); } if (present & 0x0002) { rdp_orders_in_coord(s, &self->state.memblt_x, delta); } if (present & 0x0004) { rdp_orders_in_coord(s, &self->state.memblt_y, delta); } if (present & 0x0008) { rdp_orders_in_coord(s, &self->state.memblt_cx, delta); } if (present & 0x0010) { rdp_orders_in_coord(s, &self->state.memblt_cy, delta); } if (present & 0x0020) { in_uint8(s, self->state.memblt_opcode); } if (present & 0x0040) { rdp_orders_in_coord(s, &self->state.memblt_srcx, delta); } if (present & 0x0080) { rdp_orders_in_coord(s, &self->state.memblt_srcy, delta); } if (present & 0x0100) { in_uint16_le(s, self->state.memblt_cache_idx); } bitmap = self->cache_bitmap[self->state.memblt_cache_id] [self->state.memblt_cache_idx]; if (bitmap != 0) { self->rdp_layer->mod->server_set_opcode(self->rdp_layer->mod, self->state.memblt_opcode); bmpdata = rdp_orders_convert_bitmap(self->rdp_layer->mod->rdp_bpp, self->rdp_layer->mod->xrdp_bpp, bitmap->data, bitmap->width, bitmap->height, self->cache_colormap [self->state.memblt_color_table]->colors); self->rdp_layer->mod->server_paint_rect(self->rdp_layer->mod, self->state.memblt_x, self->state.memblt_y, self->state.memblt_cx, self->state.memblt_cy, bmpdata, bitmap->width, bitmap->height, self->state.memblt_srcx, self->state.memblt_srcy); self->rdp_layer->mod->server_set_opcode(self->rdp_layer->mod, 0xcc); if (self->rdp_layer->rec_mode) { rdp_rec_check_file(self->rdp_layer); make_stream(rec_s); init_stream(rec_s, 512); s_push_layer(rec_s, iso_hdr, 4); out_uint8(rec_s, 2); out_uint8(rec_s, self->state.memblt_opcode); out_uint16_le(rec_s, self->state.memblt_x); out_uint16_le(rec_s, self->state.memblt_y); out_uint16_le(rec_s, self->state.memblt_cx); out_uint16_le(rec_s, self->state.memblt_cy); out_uint16_le(rec_s, self->state.memblt_cache_id); out_uint16_le(rec_s, self->state.memblt_cache_idx); out_uint16_le(rec_s, self->state.memblt_srcx); out_uint16_le(rec_s, self->state.memblt_srcy); rdp_rec_write_item(self->rdp_layer, rec_s); free_stream(rec_s); } if (bmpdata != bitmap->data) { g_free(bmpdata); } } } /*****************************************************************************/ /* Process a 3-way blt order */ static void APP_CC rdp_orders_process_triblt(struct rdp_orders* self, struct stream* s, int present, int delta) { /* not used */ } /*****************************************************************************/ /* Process a polyline order */ static void APP_CC rdp_orders_process_polyline(struct rdp_orders* self, struct stream* s, int present, int delta) { if (present & 0x01) { rdp_orders_in_coord(s, &self->state.polyline_x, delta); } if (present & 0x02) { rdp_orders_in_coord(s, &self->state.polyline_y, delta); } if (present & 0x04) { in_uint8(s, self->state.polyline_opcode); } if (present & 0x10) { rdp_orders_in_color(s, &self->state.polyline_fgcolor); } if (present & 0x20) { in_uint8(s, self->state.polyline_lines); } if (present & 0x40) { in_uint8(s, self->state.polyline_datasize); in_uint8a(s, self->state.polyline_data, self->state.polyline_datasize); } /* todo */ } /*****************************************************************************/ int APP_CC rdp_orders_process_orders(struct rdp_orders* self, struct stream* s, int num_orders) { int processed = 0; int order_flags = 0; int size = 0; int present = 0; int delta = 0; processed = 0; while (processed < num_orders) { in_uint8(s, order_flags); if (!(order_flags & RDP_ORDER_STANDARD)) { /* error, this should always be set */ break; } if (order_flags & RDP_ORDER_SECONDARY) { rdp_orders_process_secondary_order(self, s); } else { if (order_flags & RDP_ORDER_CHANGE) { in_uint8(s, self->state.order_type); } switch (self->state.order_type) { case RDP_ORDER_TRIBLT: case RDP_ORDER_TEXT2: size = 3; break; case RDP_ORDER_PATBLT: case RDP_ORDER_MEMBLT: case RDP_ORDER_LINE: size = 2; break; default: size = 1; break; } rdp_orders_in_present(s, &present, order_flags, size); if (order_flags & RDP_ORDER_BOUNDS) { if (!(order_flags & RDP_ORDER_LASTBOUNDS)) { rdp_orders_parse_bounds(self, s); } self->rdp_layer->mod->server_set_clip(self->rdp_layer->mod, self->state.clip_left, self->state.clip_top, (self->state.clip_right - self->state.clip_left) + 1, (self->state.clip_bottom - self->state.clip_top) + 1); } delta = order_flags & RDP_ORDER_DELTA; switch (self->state.order_type) { case RDP_ORDER_TEXT2: rdp_orders_process_text2(self, s, present, delta); break; case RDP_ORDER_DESTBLT: rdp_orders_process_destblt(self, s, present, delta); break; case RDP_ORDER_PATBLT: rdp_orders_process_patblt(self, s, present, delta); break; case RDP_ORDER_SCREENBLT: rdp_orders_process_screenblt(self, s, present, delta); break; case RDP_ORDER_LINE: rdp_orders_process_line(self, s, present, delta); break; case RDP_ORDER_RECT: rdp_orders_process_rect(self, s, present, delta); break; case RDP_ORDER_DESKSAVE: rdp_orders_process_desksave(self, s, present, delta); break; case RDP_ORDER_MEMBLT: rdp_orders_process_memblt(self, s, present, delta); break; case RDP_ORDER_TRIBLT: rdp_orders_process_triblt(self, s, present, delta); break; case RDP_ORDER_POLYLINE: rdp_orders_process_polyline(self, s, present, delta); break; default: /* error unknown order */ break; } if (order_flags & RDP_ORDER_BOUNDS) { self->rdp_layer->mod->server_reset_clip(self->rdp_layer->mod); } } processed++; } return 0; } /*****************************************************************************/ /* returns pointer, it might return bmpdata if the data dosen't need to be converted, else it mallocs it. The calling function must free it if needed */ char* APP_CC rdp_orders_convert_bitmap(int in_bpp, int out_bpp, char* bmpdata, int width, int height, int* palette) { char* out = (char *)NULL; char* src = (char *)NULL; char* dst = (char *)NULL; int i = 0; int j = 0; int red = 0; int green = 0; int blue = 0; int pixel = 0; if ((in_bpp == 8) && (out_bpp == 8)) { out = (char*)g_malloc(width * height, 0); src = bmpdata; dst = out; for (i = 0; i < height; i++) { for (j = 0; j < width; j++) { pixel = *((tui8*)src); pixel = palette[pixel]; SPLITCOLOR32(red, green, blue, pixel); pixel = COLOR8(red, green, blue); *dst = pixel; src++; dst++; } } return out; } if ((in_bpp == 8) && (out_bpp == 16)) { out = (char*)g_malloc(width * height * 2, 0); src = bmpdata; dst = out; for (i = 0; i < height; i++) { for (j = 0; j < width; j++) { pixel = *((tui8*)src); pixel = palette[pixel]; SPLITCOLOR32(red, green, blue, pixel); pixel = COLOR16(red, green, blue); *((tui16*)dst) = pixel; src++; dst += 2; } } return out; } if ((in_bpp == 8) && (out_bpp == 24)) { out = (char*)g_malloc(width * height * 4, 0); src = bmpdata; dst = out; for (i = 0; i < height; i++) { for (j = 0; j < width; j++) { pixel = *((tui8*)src); pixel = palette[pixel]; SPLITCOLOR32(red, green, blue, pixel); pixel = COLOR24RGB(red, green, blue); *((tui32*)dst) = pixel; src++; dst += 4; } } return out; } if ((in_bpp == 15) && (out_bpp == 16)) { out = (char*)g_malloc(width * height * 2, 0); src = bmpdata; dst = out; for (i = 0; i < height; i++) { for (j = 0; j < width; j++) { pixel = *((tui16*)src); SPLITCOLOR15(red, green, blue, pixel); pixel = COLOR16(red, green, blue); *((tui16*)dst) = pixel; src += 2; dst += 2; } } return out; } if ((in_bpp == 15) && (out_bpp == 24)) { out = (char*)g_malloc(width * height * 4, 0); src = bmpdata; dst = out; for (i = 0; i < height; i++) { for (j = 0; j < width; j++) { pixel = *((tui16*)src); SPLITCOLOR15(red, green, blue, pixel); pixel = COLOR24RGB(red, green, blue); *((tui32*)dst) = pixel; src += 2; dst += 4; } } return out; } if ((in_bpp == 16) && (out_bpp == 16)) { return bmpdata; } if ((in_bpp == 16) && (out_bpp == 24)) { out = (char*)g_malloc(width * height * 4, 0); src = bmpdata; dst = out; for (i = 0; i < height; i++) { for (j = 0; j < width; j++) { pixel = *((tui16*)src); SPLITCOLOR16(red, green, blue, pixel); pixel = COLOR24RGB(red, green, blue); *((tui32*)dst) = pixel; src += 2; dst += 4; } } return out; } if ((in_bpp == 24) && (out_bpp == 24)) { out = (char*)g_malloc(width * height * 4, 0); src = bmpdata; dst = out; for (i = 0; i < height; i++) { for (j = 0; j < width; j++) { blue = *((tui8*)src); src++; green = *((tui8*)src); src++; red = *((tui8*)src); src++; pixel = COLOR24RGB(red, green, blue); *((tui32*)dst) = pixel; dst += 4; } } return out; } return 0; } /*****************************************************************************/ /* returns color or 0 */ int APP_CC rdp_orders_convert_color(int in_bpp, int out_bpp, int in_color, int* palette) { int pixel = 0; int red = 0; int green = 0; int blue = 0; if ((in_bpp == 8) && (out_bpp == 8)) { pixel = palette[in_color]; SPLITCOLOR32(red, green, blue, pixel); pixel = COLOR8(red, green, blue); return pixel; } if ((in_bpp == 8) && (out_bpp == 16)) { pixel = palette[in_color]; SPLITCOLOR32(red, green, blue, pixel); pixel = COLOR16(red, green, blue); return pixel; } if ((in_bpp == 8) && (out_bpp == 24)) { pixel = palette[in_color]; SPLITCOLOR32(red, green, blue, pixel); pixel = COLOR24BGR(red, green, blue); return pixel; } if ((in_bpp == 15) && (out_bpp == 16)) { pixel = in_color; SPLITCOLOR15(red, green, blue, pixel); pixel = COLOR16(red, green, blue); return pixel; } if ((in_bpp == 15) && (out_bpp == 24)) { pixel = in_color; SPLITCOLOR15(red, green, blue, pixel); pixel = COLOR24BGR(red, green, blue); return pixel; } if ((in_bpp == 16) && (out_bpp == 16)) { return in_color; } if ((in_bpp == 16) && (out_bpp == 24)) { pixel = in_color; SPLITCOLOR16(red, green, blue, pixel); pixel = COLOR24BGR(red, green, blue); return pixel; } if ((in_bpp == 24) && (out_bpp == 24)) { return in_color; } return 0; } xrdp-0.6.0/rdp/rdp_rdp.c000066400000000000000000000747531203155130500150700ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2005-2010 librdp rdp layer */ #include "rdp.h" #ifndef NULL #define NULL 0 #endif /*****************************************************************************/ struct rdp_rdp* APP_CC rdp_rdp_create(struct mod* owner) { struct rdp_rdp* self; self = (struct rdp_rdp*)g_malloc(sizeof(struct rdp_rdp), 1); self->mod = owner; self->sec_layer = rdp_sec_create(self); self->bitmap_compression = 1; self->bitmap_cache = 1; self->desktop_save = 0; self->orders = rdp_orders_create(self); self->rec_mode = 0; return self; } /*****************************************************************************/ void APP_CC rdp_rdp_delete(struct rdp_rdp* self) { if (self == 0) { return; } rdp_orders_delete(self->orders); rdp_sec_delete(self->sec_layer); if (self->rec_fd != 0) { g_file_close(self->rec_fd); self->rec_fd = 0; } g_free(self); } /******************************************************************************/ /* Initialise an RDP packet */ int APP_CC rdp_rdp_init(struct rdp_rdp* self, struct stream* s) { if (rdp_sec_init(self->sec_layer, s, SEC_ENCRYPT) != 0) { return 1; } s_push_layer(s, rdp_hdr, 6); return 0; } /******************************************************************************/ /* Send an RDP packet */ int APP_CC rdp_rdp_send(struct rdp_rdp* self, struct stream* s, int pdu_type) { int len; int sec_flags; s_pop_layer(s, rdp_hdr); len = s->end - s->p; out_uint16_le(s, len); out_uint16_le(s, pdu_type | 0x10); out_uint16_le(s, self->sec_layer->mcs_layer->userid); sec_flags = SEC_ENCRYPT; if (rdp_sec_send(self->sec_layer, s, sec_flags) != 0) { return 1; } return 0; } /******************************************************************************/ /* Initialise an RDP data packet */ int APP_CC rdp_rdp_init_data(struct rdp_rdp* self, struct stream* s) { if (rdp_sec_init(self->sec_layer, s, SEC_ENCRYPT) != 0) { return 1; } s_push_layer(s, rdp_hdr, 18); return 0; } /******************************************************************************/ /* Send an RDP data packet */ int APP_CC rdp_rdp_send_data(struct rdp_rdp* self, struct stream* s, int pdu_data_type) { int len; int sec_flags; s_pop_layer(s, rdp_hdr); len = s->end - s->p; out_uint16_le(s, len); out_uint16_le(s, RDP_PDU_DATA | 0x10); out_uint16_le(s, self->sec_layer->mcs_layer->userid); out_uint32_le(s, self->share_id); out_uint8(s, 0); out_uint8(s, 1); out_uint16_le(s, len - 14); out_uint8(s, pdu_data_type); out_uint8(s, 0); /* compress type */ out_uint16_le(s, 0); /* compress len */ sec_flags = SEC_ENCRYPT; if (rdp_sec_send(self->sec_layer, s, sec_flags) != 0) { return 1; } return 0; } /******************************************************************************/ /* Output general capability set */ static int APP_CC rdp_rdp_out_general_caps(struct rdp_rdp* self, struct stream* s) { out_uint16_le(s, RDP_CAPSET_GENERAL); out_uint16_le(s, RDP_CAPLEN_GENERAL); out_uint16_le(s, 1); /* OS major type */ out_uint16_le(s, 3); /* OS minor type */ out_uint16_le(s, 0x200); /* Protocol version */ out_uint16_le(s, 0); /* Pad */ out_uint16_le(s, 0); /* Compression types */ out_uint16_le(s, self->use_rdp5 ? 0x40d : 0); out_uint16_le(s, 0); /* Update capability */ out_uint16_le(s, 0); /* Remote unshare capability */ out_uint16_le(s, 0); /* Compression level */ out_uint16_le(s, 0); /* Pad */ return 0; } /******************************************************************************/ /* Output bitmap capability set */ static int APP_CC rdp_rdp_out_bitmap_caps(struct rdp_rdp* self, struct stream* s) { out_uint16_le(s, RDP_CAPSET_BITMAP); out_uint16_le(s, RDP_CAPLEN_BITMAP); out_uint16_le(s, self->mod->rdp_bpp); /* Preferred BPP */ out_uint16_le(s, 1); /* Receive 1 BPP */ out_uint16_le(s, 1); /* Receive 4 BPP */ out_uint16_le(s, 1); /* Receive 8 BPP */ out_uint16_le(s, 800); /* Desktop width */ out_uint16_le(s, 600); /* Desktop height */ out_uint16_le(s, 0); /* Pad */ out_uint16_le(s, 1); /* Allow resize */ out_uint16_le(s, self->bitmap_compression); /* Support compression */ out_uint16_le(s, 0); /* Unknown */ out_uint16_le(s, 1); /* Unknown */ out_uint16_le(s, 0); /* Pad */ return 0; } /******************************************************************************/ /* Output order capability set */ static int APP_CC rdp_rdp_out_order_caps(struct rdp_rdp* self, struct stream* s) { char order_caps[32]; g_memset(order_caps, 0, 32); order_caps[0] = 1; /* dest blt */ order_caps[1] = 1; /* pat blt */ order_caps[2] = 1; /* screen blt */ order_caps[3] = self->bitmap_cache; /* memblt */ order_caps[4] = 0; /* triblt */ order_caps[8] = 1; /* line */ order_caps[9] = 1; /* line */ order_caps[10] = 1; /* rect */ order_caps[11] = self->desktop_save; /* desksave */ order_caps[13] = 1; /* memblt another above */ order_caps[14] = 1; /* triblt another above */ order_caps[20] = self->polygon_ellipse_orders; /* polygon */ order_caps[21] = self->polygon_ellipse_orders; /* polygon2 */ order_caps[22] = 0; /* todo polyline */ order_caps[25] = self->polygon_ellipse_orders; /* ellipse */ order_caps[26] = self->polygon_ellipse_orders; /* ellipse2 */ order_caps[27] = 1; /* text2 */ out_uint16_le(s, RDP_CAPSET_ORDER); out_uint16_le(s, RDP_CAPLEN_ORDER); out_uint8s(s, 20); /* Terminal desc, pad */ out_uint16_le(s, 1); /* Cache X granularity */ out_uint16_le(s, 20); /* Cache Y granularity */ out_uint16_le(s, 0); /* Pad */ out_uint16_le(s, 1); /* Max order level */ out_uint16_le(s, 0x147); /* Number of fonts */ out_uint16_le(s, 0x2a); /* Capability flags */ out_uint8p(s, order_caps, 32); /* Orders supported */ out_uint16_le(s, 0x6a1); /* Text capability flags */ out_uint8s(s, 6); /* Pad */ out_uint32_le(s, self->desktop_save * 0x38400); /* Desktop cache size */ out_uint32_le(s, 0); /* Unknown */ out_uint32_le(s, 0x4e4); /* Unknown */ return 0; } /******************************************************************************/ /* Output bitmap cache capability set */ static int APP_CC rdp_rdp_out_bmpcache_caps(struct rdp_rdp* self, struct stream* s) { int Bpp = 0; out_uint16_le(s, RDP_CAPSET_BMPCACHE); out_uint16_le(s, RDP_CAPLEN_BMPCACHE); Bpp = (self->mod->rdp_bpp + 7) / 8; out_uint8s(s, 24); /* unused */ out_uint16_le(s, 0x258); /* entries */ out_uint16_le(s, 0x100 * Bpp); /* max cell size */ out_uint16_le(s, 0x12c); /* entries */ out_uint16_le(s, 0x400 * Bpp); /* max cell size */ out_uint16_le(s, 0x106); /* entries */ out_uint16_le(s, 0x1000 * Bpp); /* max cell size */ return 0; } /******************************************************************************/ /* Output control capability set */ static int APP_CC rdp_rdp_out_control_caps(struct rdp_rdp* self, struct stream* s) { out_uint16_le(s, RDP_CAPSET_CONTROL); out_uint16_le(s, RDP_CAPLEN_CONTROL); out_uint16_le(s, 0); /* Control capabilities */ out_uint16_le(s, 0); /* Remote detach */ out_uint16_le(s, 2); /* Control interest */ out_uint16_le(s, 2); /* Detach interest */ return 0; } /******************************************************************************/ /* Output activation capability set */ static int APP_CC rdp_rdp_out_activate_caps(struct rdp_rdp* self, struct stream* s) { out_uint16_le(s, RDP_CAPSET_ACTIVATE); out_uint16_le(s, RDP_CAPLEN_ACTIVATE); out_uint16_le(s, 0); /* Help key */ out_uint16_le(s, 0); /* Help index key */ out_uint16_le(s, 0); /* Extended help key */ out_uint16_le(s, 0); /* Window activate */ return 0; } /******************************************************************************/ /* Output pointer capability set */ static int APP_CC rdp_rdp_out_pointer_caps(struct rdp_rdp* self, struct stream* s) { out_uint16_le(s, RDP_CAPSET_POINTER); out_uint16_le(s, RDP_CAPLEN_POINTER_MONO); out_uint16_le(s, 0); /* Color pointer */ out_uint16_le(s, 20); /* Cache size */ return 0; } /******************************************************************************/ /* Output share capability set */ static int APP_CC rdp_rdp_out_share_caps(struct rdp_rdp* self, struct stream* s) { out_uint16_le(s, RDP_CAPSET_SHARE); out_uint16_le(s, RDP_CAPLEN_SHARE); out_uint16_le(s, 0); /* userid */ out_uint16_le(s, 0); /* pad */ return 0; } /******************************************************************************/ /* Output color cache capability set */ static int APP_CC rdp_rdp_out_colcache_caps(struct rdp_rdp* self, struct stream* s) { out_uint16_le(s, RDP_CAPSET_COLCACHE); out_uint16_le(s, RDP_CAPLEN_COLCACHE); out_uint16_le(s, 6); /* cache size */ out_uint16_le(s, 0); /* pad */ return 0; } static char caps_0x0d[] = { 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 }; static char caps_0x0c[] = { 0x01, 0x00, 0x00, 0x00 }; static char caps_0x0e[] = { 0x01, 0x00, 0x00, 0x00 }; static char caps_0x10[] = { 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 }; /******************************************************************************/ /* Output unknown capability sets */ static int APP_CC rdp_rdp_out_unknown_caps(struct rdp_rdp* self, struct stream* s, int id, int length, char* caps) { out_uint16_le(s, id); out_uint16_le(s, length); out_uint8p(s, caps, length - 4); return 0; } #define RDP5_FLAG 0x0030 /******************************************************************************/ /* Send a confirm active PDU */ static int APP_CC rdp_rdp_send_confirm_active(struct rdp_rdp* self, struct stream* s) { int sec_flags; int caplen; sec_flags = SEC_ENCRYPT; //sec_flags = RDP5_FLAG | SEC_ENCRYPT; caplen = RDP_CAPLEN_GENERAL + RDP_CAPLEN_BITMAP + RDP_CAPLEN_ORDER + RDP_CAPLEN_BMPCACHE + RDP_CAPLEN_COLCACHE + RDP_CAPLEN_ACTIVATE + RDP_CAPLEN_CONTROL + RDP_CAPLEN_POINTER_MONO + RDP_CAPLEN_SHARE + 0x58 + 0x08 + 0x08 + 0x34 /* unknown caps */ + 4 /* w2k fix, why? */ ; if (rdp_sec_init(self->sec_layer, s, sec_flags) != 0) { return 1; } out_uint16_le(s, 2 + 14 + caplen + sizeof(RDP_SOURCE)); out_uint16_le(s, (RDP_PDU_CONFIRM_ACTIVE | 0x10)); /* Version 1 */ out_uint16_le(s, (self->sec_layer->mcs_layer->userid + 1001)); out_uint32_le(s, self->share_id); out_uint16_le(s, 0x3ea); /* userid */ out_uint16_le(s, sizeof(RDP_SOURCE)); out_uint16_le(s, caplen); out_uint8p(s, RDP_SOURCE, sizeof(RDP_SOURCE)); out_uint16_le(s, 0xd); /* num_caps */ out_uint8s(s, 2); /* pad */ rdp_rdp_out_general_caps(self, s); rdp_rdp_out_bitmap_caps(self, s); rdp_rdp_out_order_caps(self, s); rdp_rdp_out_bmpcache_caps(self, s); rdp_rdp_out_colcache_caps(self, s); rdp_rdp_out_activate_caps(self, s); rdp_rdp_out_control_caps(self, s); rdp_rdp_out_pointer_caps(self, s); rdp_rdp_out_share_caps(self, s); rdp_rdp_out_unknown_caps(self, s, 0x0d, 0x58, caps_0x0d); /* international? */ rdp_rdp_out_unknown_caps(self, s, 0x0c, 0x08, caps_0x0c); rdp_rdp_out_unknown_caps(self, s, 0x0e, 0x08, caps_0x0e); rdp_rdp_out_unknown_caps(self, s, 0x10, 0x34, caps_0x10); /* glyph cache? */ s_mark_end(s); if (rdp_sec_send(self->sec_layer, s, sec_flags) != 0) { return 1; } return 0; } /******************************************************************************/ /* Process a color pointer PDU */ static int APP_CC rdp_rdp_process_color_pointer_pdu(struct rdp_rdp* self, struct stream* s) { int cache_idx; int dlen; int mlen; struct rdp_cursor* cursor; in_uint16_le(s, cache_idx); if (cache_idx >= sizeof(self->cursors) / sizeof(cursor)) { return 1; } cursor = self->cursors + cache_idx; in_uint16_le(s, cursor->x); in_uint16_le(s, cursor->y); in_uint16_le(s, cursor->width); in_uint16_le(s, cursor->height); in_uint16_le(s, mlen); /* mask length */ in_uint16_le(s, dlen); /* data length */ if ((mlen > sizeof(cursor->mask)) || (dlen > sizeof(cursor->data))) { return 1; } in_uint8a(s, cursor->data, dlen); in_uint8a(s, cursor->mask, mlen); self->mod->server_set_cursor(self->mod, cursor->x, cursor->y, cursor->data, cursor->mask); return 0; } /******************************************************************************/ /* Process a cached pointer PDU */ static int APP_CC rdp_rdp_process_cached_pointer_pdu(struct rdp_rdp* self, struct stream* s) { int cache_idx; struct rdp_cursor* cursor; in_uint16_le(s, cache_idx); if (cache_idx >= sizeof(self->cursors) / sizeof(cursor)) { return 1; } cursor = self->cursors + cache_idx; self->mod->server_set_cursor(self->mod, cursor->x, cursor->y, cursor->data, cursor->mask); return 0; } /******************************************************************************/ /* Process a system pointer PDU */ static int APP_CC rdp_rdp_process_system_pointer_pdu(struct rdp_rdp* self, struct stream* s) { int system_pointer_type; struct rdp_cursor* cursor; in_uint16_le(s, system_pointer_type); switch (system_pointer_type) { case RDP_NULL_POINTER: cursor = (struct rdp_cursor*)g_malloc(sizeof(struct rdp_cursor), 1); g_memset(cursor->mask, 0xff, sizeof(cursor->mask)); self->mod->server_set_cursor(self->mod, cursor->x, cursor->y, cursor->data, cursor->mask); g_free(cursor); break; default: break; } return 0; } /******************************************************************************/ /* Process a pointer PDU */ static int APP_CC rdp_rdp_process_pointer_pdu(struct rdp_rdp* self, struct stream* s) { int message_type; int x; int y; int rv; rv = 0; in_uint16_le(s, message_type); in_uint8s(s, 2); /* pad */ switch (message_type) { case RDP_POINTER_MOVE: in_uint16_le(s, x); in_uint16_le(s, y); break; case RDP_POINTER_COLOR: rv = rdp_rdp_process_color_pointer_pdu(self, s); break; case RDP_POINTER_CACHED: rv = rdp_rdp_process_cached_pointer_pdu(self, s); break; case RDP_POINTER_SYSTEM: rv = rdp_rdp_process_system_pointer_pdu(self, s); break; default: break; } return rv; } /******************************************************************************/ /* Process bitmap updates */ static void APP_CC rdp_rdp_process_bitmap_updates(struct rdp_rdp* self, struct stream* s) { int num_updates = 0; int left = 0; int top = 0; int right = 0; int bottom = 0; int width = 0; int height = 0; int cx = 0; int cy = 0; int bpp = 0; int Bpp = 0; int compress = 0; int bufsize = 0; int size = 0; int i = 0; int x = 0; int y = 0; char* data = NULL; char* bmpdata0 = NULL; char* bmpdata1 = NULL; in_uint16_le(s, num_updates); for (i = 0; i < num_updates; i++) { in_uint16_le(s, left); in_uint16_le(s, top); in_uint16_le(s, right); in_uint16_le(s, bottom); in_uint16_le(s, width); in_uint16_le(s, height); in_uint16_le(s, bpp); Bpp = (bpp + 7) / 8; in_uint16_le(s, compress); in_uint16_le(s, bufsize); cx = (right - left) + 1; cy = (bottom - top) + 1; bmpdata0 = (char*)g_malloc(width * height * Bpp, 0); if (compress) { if (compress & 0x400) { size = bufsize; } else { in_uint8s(s, 2); /* pad */ in_uint16_le(s, size); in_uint8s(s, 4); /* line_size, final_size */ } in_uint8p(s, data, size); rdp_bitmap_decompress(bmpdata0, width, height, data, size, Bpp); bmpdata1 = rdp_orders_convert_bitmap(bpp, self->mod->xrdp_bpp, bmpdata0, width, height, self->colormap.colors); self->mod->server_paint_rect(self->mod, left, top, cx, cy, bmpdata1, width, height, 0, 0); } else /* not compressed */ { for (y = 0; y < height; y++) { data = bmpdata0 + ((height - y) - 1) * (width * Bpp); if (Bpp == 1) { for (x = 0; x < width; x++) { in_uint8(s, data[x]); } } else if (Bpp == 2) { for (x = 0; x < width; x++) { in_uint16_le(s, ((tui16*)data)[x]); } } else if (Bpp == 3) { for (x = 0; x < width; x++) { in_uint8(s, data[x * 3 + 0]); in_uint8(s, data[x * 3 + 1]); in_uint8(s, data[x * 3 + 2]); } } } bmpdata1 = rdp_orders_convert_bitmap(bpp, self->mod->xrdp_bpp, bmpdata0, width, height, self->colormap.colors); self->mod->server_paint_rect(self->mod, left, top, cx, cy, bmpdata1, width, height, 0, 0); } if (bmpdata0 != bmpdata1) { g_free(bmpdata1); } g_free(bmpdata0); } } /******************************************************************************/ /* Process a palette update */ static void APP_CC rdp_rdp_process_palette(struct rdp_rdp* self, struct stream* s) { int i; int r; int g; int b; in_uint8s(s, 2); /* pad */ in_uint16_le(s, self->colormap.ncolors); in_uint8s(s, 2); /* pad */ for (i = 0; i < self->colormap.ncolors; i++) { in_uint8(s, r); in_uint8(s, g); in_uint8(s, b); self->colormap.colors[i] = (r << 16) | (g << 8) | b; } //ui_set_colormap(hmap); } /******************************************************************************/ /* Process an update PDU */ static int APP_CC rdp_rdp_process_update_pdu(struct rdp_rdp* self, struct stream* s) { int update_type; int count; in_uint16_le(s, update_type); self->mod->server_begin_update(self->mod); switch (update_type) { case RDP_UPDATE_ORDERS: in_uint8s(s, 2); /* pad */ in_uint16_le(s, count); in_uint8s(s, 2); /* pad */ rdp_orders_process_orders(self->orders, s, count); break; case RDP_UPDATE_BITMAP: rdp_rdp_process_bitmap_updates(self, s); break; case RDP_UPDATE_PALETTE: rdp_rdp_process_palette(self, s); break; case RDP_UPDATE_SYNCHRONIZE: break; default: break; } self->mod->server_end_update(self->mod); return 0; } /******************************************************************************/ void APP_CC rdp_rdp_out_unistr(struct stream* s, char* text) { int i; i = 0; while (text[i] != 0) { out_uint8(s, text[i]); out_uint8(s, 0); i++; } out_uint8(s, 0); out_uint8(s, 0); } /******************************************************************************/ int APP_CC rdp_rdp_send_login_info(struct rdp_rdp* self, int flags) { int len_domain; int len_username; int len_password; int len_program; int len_directory; int sec_flags; struct stream* s; DEBUG(("in rdp_rdp_send_login_info")); make_stream(s); init_stream(s, 8192); len_domain = 2 * g_strlen(self->mod->domain); len_username = 2 * g_strlen(self->mod->username); len_password = 2 * g_strlen(self->mod->password); len_program = 2 * g_strlen(self->mod->program); len_directory = 2 * g_strlen(self->mod->directory); sec_flags = SEC_LOGON_INFO | SEC_ENCRYPT; if (rdp_sec_init(self->sec_layer, s, sec_flags) != 0) { free_stream(s); DEBUG(("out rdp_rdp_send_login_info error 1")); return 1; } out_uint32_le(s, 0); out_uint32_le(s, flags); out_uint16_le(s, len_domain); out_uint16_le(s, len_username); out_uint16_le(s, len_password); out_uint16_le(s, len_program); out_uint16_le(s, len_directory); rdp_rdp_out_unistr(s, self->mod->domain); rdp_rdp_out_unistr(s, self->mod->username); rdp_rdp_out_unistr(s, self->mod->password); rdp_rdp_out_unistr(s, self->mod->program); rdp_rdp_out_unistr(s, self->mod->directory); s_mark_end(s); if (rdp_sec_send(self->sec_layer, s, sec_flags) != 0) { free_stream(s); DEBUG(("out rdp_rdp_send_login_info error 2")); return 1; } free_stream(s); DEBUG(("out rdp_rdp_send_login_info")); return 0; } /******************************************************************************/ int APP_CC rdp_rdp_connect(struct rdp_rdp* self, char* ip, char* port) { int flags; DEBUG(("in rdp_rdp_connect")); flags = RDP_LOGON_NORMAL; if (g_strlen(self->mod->password) > 0) { flags |= RDP_LOGON_AUTO; } if (rdp_sec_connect(self->sec_layer, ip, port) != 0) { DEBUG(("out rdp_rdp_connect error rdp_sec_connect failed")); return 1; } if (rdp_rdp_send_login_info(self, flags) != 0) { DEBUG(("out rdp_rdp_connect error rdp_rdp_send_login_info failed")); return 1; } DEBUG(("out rdp_rdp_connect")); return 0; } /******************************************************************************/ int APP_CC rdp_rdp_send_input(struct rdp_rdp* self, struct stream* s, int time, int message_type, int device_flags, int param1, int param2) { if (rdp_rdp_init_data(self, s) != 0) { return 1; } out_uint16_le(s, 1); /* number of events */ out_uint16_le(s, 0); out_uint32_le(s, time); out_uint16_le(s, message_type); out_uint16_le(s, device_flags); out_uint16_le(s, param1); out_uint16_le(s, param2); s_mark_end(s); if (rdp_rdp_send_data(self, s, RDP_DATA_PDU_INPUT) != 0) { return 1; } return 0; } /******************************************************************************/ int APP_CC rdp_rdp_send_invalidate(struct rdp_rdp* self, struct stream* s, int left, int top, int width, int height) { if (rdp_rdp_init_data(self, s) != 0) { return 1; } out_uint32_le(s, 1); out_uint16_le(s, left); out_uint16_le(s, top); out_uint16_le(s, (left + width) - 1); out_uint16_le(s, (top + height) - 1); s_mark_end(s); if (rdp_rdp_send_data(self, s, 33) != 0) { return 1; } return 0; } /******************************************************************************/ int APP_CC rdp_rdp_recv(struct rdp_rdp* self, struct stream* s, int* type) { int len; int pdu_type; int chan; chan = 0; DEBUG(("in rdp_rdp_recv")); if (s->next_packet >= s->end || s->next_packet == 0) { if (rdp_sec_recv(self->sec_layer, s, &chan) != 0) { DEBUG(("error in rdp_rdp_recv, rdp_sec_recv failed")); return 1; } s->next_packet = s->p; } else { chan = MCS_GLOBAL_CHANNEL; s->p = s->next_packet; } if (chan == MCS_GLOBAL_CHANNEL) { in_uint16_le(s, len); DEBUG(("rdp_rdp_recv got %d len", len)); if (len == 0x8000) { s->next_packet += 8; DEBUG(("out rdp_rdp_recv")); return 0; } in_uint16_le(s, pdu_type); in_uint8s(s, 2); *type = pdu_type & 0xf; s->next_packet += len; } else { /* todo, process channel data */ DEBUG(("got channel data channel %d", chan)); s->next_packet = s->end; } DEBUG(("out rdp_rdp_recv")); return 0; } /******************************************************************************/ static int APP_CC rdp_rdp_process_disconnect_pdu(struct rdp_rdp* self, struct stream* s) { return 0; } /******************************************************************************/ int APP_CC rdp_rdp_process_data_pdu(struct rdp_rdp* self, struct stream* s) { int data_pdu_type; int ctype; int len; int rv; rv = 0; in_uint8s(s, 6); /* shareid, pad, streamid */ in_uint16_le(s, len); in_uint8(s, data_pdu_type); in_uint8(s, ctype); in_uint8s(s, 2); /* clen */ switch (data_pdu_type) { case RDP_DATA_PDU_UPDATE: rv = rdp_rdp_process_update_pdu(self, s); break; case RDP_DATA_PDU_CONTROL: break; case RDP_DATA_PDU_SYNCHRONISE: break; case RDP_DATA_PDU_POINTER: rv = rdp_rdp_process_pointer_pdu(self, s); break; case RDP_DATA_PDU_PLAY_SOUND: break; case RDP_DATA_PDU_LOGON: break; case RDP_DATA_PDU_DISCONNECT: rv = rdp_rdp_process_disconnect_pdu(self, s); break; default: break; } return rv; } /******************************************************************************/ /* Process a bitmap capability set */ static void APP_CC rdp_rdp_process_general_caps(struct rdp_rdp* self, struct stream* s) { } /******************************************************************************/ /* Process a bitmap capability set */ static void APP_CC rdp_rdp_process_bitmap_caps(struct rdp_rdp* self, struct stream* s) { int width = 0; int height = 0; int bpp = 0; in_uint16_le(s, bpp); in_uint8s(s, 6); in_uint16_le(s, width); in_uint16_le(s, height); self->mod->rdp_bpp = bpp; /* todo, call reset if needed and use width and height */ } /******************************************************************************/ /* Process server capabilities */ /* returns error */ static int APP_CC rdp_rdp_process_server_caps(struct rdp_rdp* self, struct stream* s, int len) { int n = 0; int ncapsets = 0; int capset_type = 0; int capset_length = 0; char* next = NULL; char* start = NULL; start = s->p; in_uint16_le(s, ncapsets); in_uint8s(s, 2); /* pad */ for (n = 0; n < ncapsets; n++) { if (s->p > start + len) { return 0; } in_uint16_le(s, capset_type); in_uint16_le(s, capset_length); next = (s->p + capset_length) - 4; switch (capset_type) { case RDP_CAPSET_GENERAL: rdp_rdp_process_general_caps(self, s); break; case RDP_CAPSET_BITMAP: rdp_rdp_process_bitmap_caps(self, s); break; default: break; } s->p = next; } return 0; } /******************************************************************************/ /* Send a control PDU */ /* returns error */ static int APP_CC rdp_rdp_send_control(struct rdp_rdp* self, struct stream* s, int action) { if (rdp_rdp_init_data(self, s) != 0) { return 1; } out_uint16_le(s, action); out_uint16_le(s, 0); /* userid */ out_uint32_le(s, 0); /* control id */ s_mark_end(s); if (rdp_rdp_send_data(self, s, RDP_DATA_PDU_CONTROL) != 0) { return 1; } return 0; } /******************************************************************************/ /* Send a synchronisation PDU */ /* returns error */ static int APP_CC rdp_rdp_send_synchronise(struct rdp_rdp* self, struct stream* s) { if (rdp_rdp_init_data(self, s) != 0) { return 1; } out_uint16_le(s, 1); /* type */ out_uint16_le(s, 1002); s_mark_end(s); if (rdp_rdp_send_data(self, s, RDP_DATA_PDU_SYNCHRONISE) != 0) { return 1; } return 0; } /******************************************************************************/ /* Send an (empty) font information PDU */ static int APP_CC rdp_rdp_send_fonts(struct rdp_rdp* self, struct stream* s, int seq) { if (rdp_rdp_init_data(self, s) != 0) { return 1; } out_uint16_le(s, 0); /* number of fonts */ out_uint16_le(s, 0); /* pad? */ out_uint16_le(s, seq); /* unknown */ out_uint16_le(s, 0x32); /* entry size */ s_mark_end(s); if (rdp_rdp_send_data(self, s, RDP_DATA_PDU_FONT2) != 0) { return 1; } return 0; } /******************************************************************************/ /* Respond to a demand active PDU */ int APP_CC rdp_rdp_process_demand_active(struct rdp_rdp* self, struct stream* s) { int type = 0; int len_src_descriptor = 0; int len_combined_caps = 0; in_uint32_le(s, self->share_id); in_uint16_le(s, len_src_descriptor); in_uint16_le(s, len_combined_caps); in_uint8s(s, len_src_descriptor); rdp_rdp_process_server_caps(self, s, len_combined_caps); rdp_rdp_send_confirm_active(self, s); rdp_rdp_send_synchronise(self, s); rdp_rdp_send_control(self, s, RDP_CTL_COOPERATE); rdp_rdp_send_control(self, s, RDP_CTL_REQUEST_CONTROL); rdp_rdp_recv(self, s, &type); /* RDP_PDU_SYNCHRONIZE */ rdp_rdp_recv(self, s, &type); /* RDP_CTL_COOPERATE */ rdp_rdp_recv(self, s, &type); /* RDP_CTL_GRANT_CONTROL */ rdp_rdp_send_input(self, s, 0, RDP_INPUT_SYNCHRONIZE, 0, 0, 0); rdp_rdp_send_fonts(self, s, 1); rdp_rdp_send_fonts(self, s, 2); rdp_rdp_recv(self, s, &type); /* RDP_PDU_UNKNOWN 0x28 (Fonts?) */ rdp_orders_reset_state(self->orders); return 0; } /******************************************************************************/ int APP_CC rdp_rec_check_file(struct rdp_rdp* self) { char file_name[256]; int index = 0; int len = 0; struct stream* s = (struct stream *)NULL; g_memset(file_name,0,sizeof(char) * 256); if (self->rec_fd == 0) { index = 1; g_sprintf(file_name, "rec%8.8d.rec", index); while (g_file_exist(file_name)) { index++; if (index >= 9999) { return 1; } g_sprintf(file_name, "rec%8.8d.rec", index); } self->rec_fd = g_file_open(file_name); make_stream(s); init_stream(s, 8192); out_uint8a(s, "XRDPREC1", 8); out_uint8s(s, 8); s_mark_end(s); len = s->end - s->data; g_file_write(self->rec_fd, s->data, len); free_stream(s); } return 0; } /******************************************************************************/ int APP_CC rdp_rec_write_item(struct rdp_rdp* self, struct stream* s) { int len = 0; int time = 0; if (self->rec_fd == 0) { return 1; } time = g_time1(); out_uint32_le(s, time); s_mark_end(s); len = s->end - s->data; s_pop_layer(s, iso_hdr); out_uint32_le(s, len); g_file_write(self->rec_fd, s->data, len); return 0; } xrdp-0.6.0/rdp/rdp_sec.c000066400000000000000000000445361203155130500150510ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2005-2010 librdp secure layer */ #include "rdp.h" static char g_pad_54[40] = { 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54 }; static char g_pad_92[48] = { 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92 }; /*****************************************************************************/ struct rdp_sec* APP_CC rdp_sec_create(struct rdp_rdp* owner) { struct rdp_sec* self; self = (struct rdp_sec*)g_malloc(sizeof(struct rdp_sec), 1); self->rdp_layer = owner; make_stream(self->client_mcs_data); init_stream(self->client_mcs_data, 8192); make_stream(self->server_mcs_data); init_stream(self->server_mcs_data, 8192); self->mcs_layer = rdp_mcs_create(self, self->client_mcs_data, self->server_mcs_data); self->decrypt_rc4_info = ssl_rc4_info_create(); self->encrypt_rc4_info = ssl_rc4_info_create(); self->lic_layer = rdp_lic_create(self); return self; } /*****************************************************************************/ void APP_CC rdp_sec_delete(struct rdp_sec* self) { if (self == 0) { return; } rdp_lic_delete(self->lic_layer); rdp_mcs_delete(self->mcs_layer); free_stream(self->client_mcs_data); free_stream(self->server_mcs_data); ssl_rc4_info_delete(self->decrypt_rc4_info); ssl_rc4_info_delete(self->encrypt_rc4_info); g_free(self); } /*****************************************************************************/ /* Reduce key entropy from 64 to 40 bits */ static void APP_CC rdp_sec_make_40bit(char* key) { key[0] = 0xd1; key[1] = 0x26; key[2] = 0x9e; } /*****************************************************************************/ /* returns error */ /* update an encryption key */ static int APP_CC rdp_sec_update(char* key, char* update_key, int key_len) { char shasig[20]; void* sha1_info; void* md5_info; void* rc4_info; sha1_info = ssl_sha1_info_create(); md5_info = ssl_md5_info_create(); rc4_info = ssl_rc4_info_create(); ssl_sha1_clear(sha1_info); ssl_sha1_transform(sha1_info, update_key, key_len); ssl_sha1_transform(sha1_info, g_pad_54, 40); ssl_sha1_transform(sha1_info, key, key_len); ssl_sha1_complete(sha1_info, shasig); ssl_md5_clear(md5_info); ssl_md5_transform(md5_info, update_key, key_len); ssl_md5_transform(md5_info, g_pad_92, 48); ssl_md5_transform(md5_info, shasig, 20); ssl_md5_complete(md5_info, key); ssl_rc4_set_key(rc4_info, key, key_len); ssl_rc4_crypt(rc4_info, key, key_len); if (key_len == 8) { rdp_sec_make_40bit(key); } ssl_sha1_info_delete(sha1_info); ssl_md5_info_delete(md5_info); ssl_rc4_info_delete(rc4_info); return 0; } /*****************************************************************************/ static void APP_CC rdp_sec_decrypt(struct rdp_sec* self, char* data, int len) { if (self->decrypt_use_count == 4096) { rdp_sec_update(self->decrypt_key, self->decrypt_update_key, self->rc4_key_len); ssl_rc4_set_key(self->decrypt_rc4_info, self->decrypt_key, self->rc4_key_len); self->decrypt_use_count = 0; } ssl_rc4_crypt(self->decrypt_rc4_info, data, len); self->decrypt_use_count++; } /*****************************************************************************/ /* returns error */ int APP_CC rdp_sec_recv(struct rdp_sec* self, struct stream* s, int* chan) { int flags; DEBUG((" in rdp_sec_recv")); if (rdp_mcs_recv(self->mcs_layer, s, chan) != 0) { DEBUG((" error in rdp_sec_recv, rdp_mcs_recv failed")); return 1; } in_uint32_le(s, flags); DEBUG((" rdp_sec_recv flags %8.8x", flags)); if (flags & SEC_ENCRYPT) /* 0x08 */ { in_uint8s(s, 8); /* signature */ rdp_sec_decrypt(self, s->p, s->end - s->p); } if (flags & SEC_LICENCE_NEG) /* 0x80 */ { DEBUG((" in rdp_sec_recv, got SEC_LICENCE_NEG")); rdp_lic_process(self->lic_layer, s); *chan = 0; } DEBUG((" out rdp_sec_recv")); return 0; } /*****************************************************************************/ /* prepare client mcs data to send in mcs layer */ static void APP_CC rdp_sec_out_mcs_data(struct rdp_sec* self) { struct stream* s; int hostlen; int length; s = self->client_mcs_data; init_stream(s, 512); self->rdp_layer->mod->hostname[15] = 0; /* limit length to 15 */ hostlen = 2 * g_strlen(self->rdp_layer->mod->hostname); length = 158 + 76 + 12 + 4; /* Generic Conference Control (T.124) ConferenceCreateRequest */ out_uint16_be(s, 5); out_uint16_be(s, 0x14); out_uint8(s, 0x7c); out_uint16_be(s, 1); out_uint16_be(s, (length | 0x8000)); /* remaining length */ out_uint16_be(s, 8); /* length? */ out_uint16_be(s, 16); out_uint8(s, 0); out_uint16_le(s, 0xc001); out_uint8(s, 0); out_uint32_le(s, 0x61637544); /* OEM ID: "Duca", as in Ducati. */ out_uint16_be(s, ((length - 14) | 0x8000)); /* remaining length */ /* Client information */ out_uint16_le(s, SEC_TAG_CLI_INFO); out_uint16_le(s, 212); /* length */ out_uint16_le(s, 1); /* RDP version. 1 == RDP4, 4 == RDP5. */ out_uint16_le(s, 8); out_uint16_le(s, self->rdp_layer->mod->width); out_uint16_le(s, self->rdp_layer->mod->height); out_uint16_le(s, 0xca01); out_uint16_le(s, 0xaa03); out_uint32_le(s, self->rdp_layer->mod->keylayout); out_uint32_le(s, 2600); /* Client build */ /* Unicode name of client, padded to 32 bytes */ rdp_rdp_out_unistr(s, self->rdp_layer->mod->hostname); out_uint8s(s, 30 - hostlen); out_uint32_le(s, 4); out_uint32_le(s, 0); out_uint32_le(s, 12); out_uint8s(s, 64); /* reserved? 4 + 12 doublewords */ out_uint16_le(s, 0xca01); /* color depth? */ out_uint16_le(s, 1); out_uint32_le(s, 0); out_uint8(s, self->rdp_layer->mod->rdp_bpp); out_uint16_le(s, 0x0700); out_uint8(s, 0); out_uint32_le(s, 1); out_uint8s(s, 64); /* End of client info */ out_uint16_le(s, SEC_TAG_CLI_4); out_uint16_le(s, 12); out_uint32_le(s, 9); out_uint32_le(s, 0); /* Client encryption settings */ out_uint16_le(s, SEC_TAG_CLI_CRYPT); out_uint16_le(s, 12); /* length */ /* encryption supported, 128-bit supported */ out_uint32_le(s, 0x3); out_uint32_le(s, 0); /* Unknown */ s_mark_end(s); } /*****************************************************************************/ /* Parse a public key structure */ /* returns boolean */ static int APP_CC rdp_sec_parse_public_key(struct rdp_sec* self, struct stream* s, char* modulus, char* exponent) { int magic; int modulus_len; in_uint32_le(s, magic); if (magic != SEC_RSA_MAGIC) { return 0; } in_uint32_le(s, modulus_len); if (modulus_len != SEC_MODULUS_SIZE + SEC_PADDING_SIZE) { return 0; } in_uint8s(s, 8); in_uint8a(s, exponent, SEC_EXPONENT_SIZE); in_uint8a(s, modulus, SEC_MODULUS_SIZE); in_uint8s(s, SEC_PADDING_SIZE); return s_check(s); } /*****************************************************************************/ /* Parse a crypto information structure */ /* returns boolean */ static int APP_CC rdp_sec_parse_crypt_info(struct rdp_sec* self, struct stream* s, char* modulus, char* exponent) { int random_len; int rsa_info_len; int flags; int tag; int length; char* next_tag; char* end; in_uint32_le(s, self->rc4_key_size); /* 1 = 40-bit, 2 = 128-bit */ in_uint32_le(s, self->crypt_level); /* 1 = low, 2 = medium, 3 = high */ if (self->crypt_level == 0) /* no encryption */ { return 0; } in_uint32_le(s, random_len); in_uint32_le(s, rsa_info_len); if (random_len != SEC_RANDOM_SIZE) { return 0; } in_uint8a(s, self->server_random, random_len); /* RSA info */ end = s->p + rsa_info_len; if (end > s->end) { return 0; } in_uint32_le(s, flags); /* 1 = RDP4-style, 0x80000002 = X.509 */ if (flags & 1) { in_uint8s(s, 8); /* unknown */ while (s->p < end) { in_uint16_le(s, tag); in_uint16_le(s, length); next_tag = s->p + length; DEBUG((" rdp_sec_parse_crypt_info tag %d length %d", tag, length)); switch (tag) { case SEC_TAG_PUBKEY: if (!rdp_sec_parse_public_key(self, s, modulus, exponent)) { return 0; } break; case SEC_TAG_KEYSIG: break; default: break; } s->p = next_tag; } } else { /* todo */ return 0; } return s_check_end(s); } /*****************************************************************************/ static void APP_CC rdp_sec_rsa_op(char* out, char* in, char* mod, char* exp) { ssl_mod_exp(out, SEC_MODULUS_SIZE, /* 64 */ in, SEC_RANDOM_SIZE, /* 32 */ mod, SEC_MODULUS_SIZE, /* 64 */ exp, SEC_EXPONENT_SIZE); /* 4 */ } /*****************************************************************************/ void APP_CC rdp_sec_hash_48(char* out, char* in, char* salt1, char* salt2, int salt) { int i; void* sha1_info; void* md5_info; char pad[4]; char sha1_sig[20]; char md5_sig[16]; sha1_info = ssl_sha1_info_create(); md5_info = ssl_md5_info_create(); for (i = 0; i < 3; i++) { g_memset(pad, salt + i, 4); ssl_sha1_clear(sha1_info); ssl_sha1_transform(sha1_info, pad, i + 1); ssl_sha1_transform(sha1_info, in, 48); ssl_sha1_transform(sha1_info, salt1, 32); ssl_sha1_transform(sha1_info, salt2, 32); ssl_sha1_complete(sha1_info, sha1_sig); ssl_md5_clear(md5_info); ssl_md5_transform(md5_info, in, 48); ssl_md5_transform(md5_info, sha1_sig, 20); ssl_md5_complete(md5_info, md5_sig); g_memcpy(out + i * 16, md5_sig, 16); } ssl_sha1_info_delete(sha1_info); ssl_md5_info_delete(md5_info); } /*****************************************************************************/ void APP_CC rdp_sec_hash_16(char* out, char* in, char* salt1, char* salt2) { void* md5_info; md5_info = ssl_md5_info_create(); ssl_md5_clear(md5_info); ssl_md5_transform(md5_info, in, 16); ssl_md5_transform(md5_info, salt1, 32); ssl_md5_transform(md5_info, salt2, 32); ssl_md5_complete(md5_info, out); ssl_md5_info_delete(md5_info); } /*****************************************************************************/ static int APP_CC rdp_sec_generate_keys(struct rdp_sec* self) { char session_key[48]; char temp_hash[48]; char input[48]; g_memcpy(input, self->client_random, 24); g_memcpy(input + 24, self->server_random, 24); rdp_sec_hash_48(temp_hash, input, self->client_random, self->server_random, 65); rdp_sec_hash_48(session_key, temp_hash, self->client_random, self->server_random, 88); g_memcpy(self->sign_key, session_key, 16); rdp_sec_hash_16(self->decrypt_key, session_key + 16, self->client_random, self->server_random); rdp_sec_hash_16(self->encrypt_key, session_key + 32, self->client_random, self->server_random); DEBUG((" rdp_sec_generate_keys, rc4_key_size is %d", self->rc4_key_size)); DEBUG((" rdp_sec_generate_keys, crypt_level is %d", self->crypt_level)); if (self->rc4_key_size == 1) { rdp_sec_make_40bit(self->sign_key); rdp_sec_make_40bit(self->encrypt_key); rdp_sec_make_40bit(self->decrypt_key); self->rc4_key_len = 8; } else { self->rc4_key_len = 16; } g_memcpy(self->decrypt_update_key, self->decrypt_key, 16); g_memcpy(self->encrypt_update_key, self->encrypt_key, 16); ssl_rc4_set_key(self->decrypt_rc4_info, self->decrypt_key, self->rc4_key_len); ssl_rc4_set_key(self->encrypt_rc4_info, self->encrypt_key, self->rc4_key_len); return 0; } /*****************************************************************************/ /* Process crypto information blob */ static void APP_CC rdp_sec_process_crypt_info(struct rdp_sec* self, struct stream* s) { char modulus[64]; char exponent[64]; g_memset(modulus, 0, sizeof(modulus)); g_memset(exponent, 0, sizeof(exponent)); if (!rdp_sec_parse_crypt_info(self, s, modulus, exponent)) { DEBUG((" error in rdp_sec_process_crypt_info")); return; } /* Generate a client random, and determine encryption keys */ g_random(self->client_random, 32); rdp_sec_rsa_op(self->client_crypt_random, self->client_random, modulus, exponent); rdp_sec_generate_keys(self); } /*****************************************************************************/ /* Process connect response data blob */ static void APP_CC rdp_sec_process_mcs_data(struct rdp_sec* self) { int tag; int length; int len; char* next_tag; struct stream* s; s = self->server_mcs_data; s->p = s->data; in_uint8s(s, 21); /* header (T.124 ConferenceCreateResponse) */ in_uint8(s, len); if (len & 0x80) { in_uint8(s, len); } while (s->p < s->end) { in_uint16_le(s, tag); in_uint16_le(s, length); DEBUG((" rdp_sec_process_mcs_data tag %d length %d", tag, length)); if (length <= 4) { return; } next_tag = (s->p + length) - 4; switch (tag) { case SEC_TAG_SRV_INFO: //rdp_sec_process_srv_info(self, s); break; case SEC_TAG_SRV_CRYPT: rdp_sec_process_crypt_info(self, s); break; case SEC_TAG_SRV_CHANNELS: break; default: break; } s->p = next_tag; } } /*****************************************************************************/ /* Transfer the client random to the server */ /* returns error */ static int APP_CC rdp_sec_establish_key(struct rdp_sec* self) { int length; int flags; struct stream* s; DEBUG((" sending client random")); make_stream(s); init_stream(s, 8192); length = SEC_MODULUS_SIZE + SEC_PADDING_SIZE; flags = SEC_CLIENT_RANDOM; if (rdp_sec_init(self, s, flags) != 0) { free_stream(s); return 1; } out_uint32_le(s, length); out_uint8p(s, self->client_crypt_random, SEC_MODULUS_SIZE); out_uint8s(s, SEC_PADDING_SIZE); s_mark_end(s); if (rdp_sec_send(self, s, flags) != 0) { free_stream(s); return 1; } free_stream(s); return 0; } /*****************************************************************************/ /* Establish a secure connection */ int APP_CC rdp_sec_connect(struct rdp_sec* self, char* ip, char* port) { DEBUG((" in rdp_sec_connect")); rdp_sec_out_mcs_data(self); if (rdp_mcs_connect(self->mcs_layer, ip, port) != 0) { DEBUG((" out rdp_sec_connect error rdp_mcs_connect failed")); return 1; } rdp_sec_process_mcs_data(self); if (rdp_sec_establish_key(self) != 0) { DEBUG((" out rdp_sec_connect error rdp_sec_establish_key failed")); return 1; } DEBUG((" out rdp_sec_connect")); return 0; } /*****************************************************************************/ /* returns error */ int APP_CC rdp_sec_init(struct rdp_sec* self, struct stream* s, int flags) { if (rdp_mcs_init(self->mcs_layer, s) != 0) { return 1; } if (flags & SEC_ENCRYPT) { s_push_layer(s, sec_hdr, 12); } else { s_push_layer(s, sec_hdr, 4); } return 0; } /*****************************************************************************/ /* Output a uint32 into a buffer (little-endian) */ void APP_CC rdp_sec_buf_out_uint32(char* buffer, int value) { buffer[0] = value & 0xff; buffer[1] = (value >> 8) & 0xff; buffer[2] = (value >> 16) & 0xff; buffer[3] = (value >> 24) & 0xff; } /*****************************************************************************/ /* Generate a MAC hash (5.2.3.1), using a combination of SHA1 and MD5 */ void APP_CC rdp_sec_sign(char* signature, int siglen, char* session_key, int keylen, char* data, int datalen) { char shasig[20]; char md5sig[16]; char lenhdr[4]; void* sha1_context; void* md5_context; rdp_sec_buf_out_uint32(lenhdr, datalen); sha1_context = ssl_sha1_info_create(); ssl_sha1_clear(sha1_context); ssl_sha1_transform(sha1_context, session_key, keylen); ssl_sha1_transform(sha1_context, g_pad_54, 40); ssl_sha1_transform(sha1_context, lenhdr, 4); ssl_sha1_transform(sha1_context, data, datalen); ssl_sha1_complete(sha1_context, shasig); ssl_sha1_info_delete(sha1_context); md5_context = ssl_md5_info_create(); ssl_md5_clear(md5_context); ssl_md5_transform(md5_context, session_key, keylen); ssl_md5_transform(md5_context, g_pad_92, 48); ssl_md5_transform(md5_context, shasig, 20); ssl_md5_complete(md5_context, md5sig); ssl_md5_info_delete(md5_context); g_memcpy(signature, md5sig, siglen); } /*****************************************************************************/ /* Encrypt data using RC4 */ static void APP_CC rdp_sec_encrypt(struct rdp_sec* self, char* data, int length) { if (self->encrypt_use_count == 4096) { rdp_sec_update(self->encrypt_key, self->encrypt_update_key, self->rc4_key_len); ssl_rc4_set_key(self->encrypt_rc4_info, self->encrypt_key, self->rc4_key_len); self->encrypt_use_count = 0; } ssl_rc4_crypt(self->encrypt_rc4_info, data, length); self->encrypt_use_count++; } /*****************************************************************************/ /* returns error */ int APP_CC rdp_sec_send(struct rdp_sec* self, struct stream* s, int flags) { int datalen; DEBUG((" in rdp_sec_send flags %8.8x", flags)); s_pop_layer(s, sec_hdr); out_uint32_le(s, flags); if (flags & SEC_ENCRYPT) { datalen = (s->end - s->p) - 8; rdp_sec_sign(s->p, 8, self->sign_key, self->rc4_key_len, s->p + 8, datalen); rdp_sec_encrypt(self, s->p + 8, datalen); } if (rdp_mcs_send(self->mcs_layer, s) != 0) { DEBUG((" out rdp_sec_send, rdp_mcs_send failed")); return 1; } DEBUG((" out rdp_sec_send")); return 0; } xrdp-0.6.0/rdp/rdp_tcp.c000066400000000000000000000101531203155130500150510ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2005-2010 librdp tcp layer */ #include "rdp.h" /*****************************************************************************/ struct rdp_tcp* APP_CC rdp_tcp_create(struct rdp_iso* owner) { struct rdp_tcp* self; self = (struct rdp_tcp*)g_malloc(sizeof(struct rdp_tcp), 1); self->iso_layer = owner; return self; } /*****************************************************************************/ void APP_CC rdp_tcp_delete(struct rdp_tcp* self) { g_free(self); } /*****************************************************************************/ /* get out stream ready for data */ /* returns error */ int APP_CC rdp_tcp_init(struct rdp_tcp* self, struct stream* s) { init_stream(s, 8192); return 0; } /*****************************************************************************/ /* returns error */ int APP_CC rdp_tcp_recv(struct rdp_tcp* self, struct stream* s, int len) { int rcvd; DEBUG((" in rdp_tcp_recv gota get %d bytes on sck %d", len, self->sck)); if (self->sck_closed) { DEBUG((" out rdp_tcp_recv error sck closed")); return 1; } init_stream(s, len); while (len > 0) { rcvd = g_tcp_recv(self->sck, s->end, len, 0); if (rcvd == -1) { if (g_tcp_last_error_would_block(self->sck)) { g_tcp_can_recv(self->sck, 10); } else { self->sck_closed = 1; DEBUG((" out rdp_tcp_recv error unknown")); return 1; } } else if (rcvd == 0) { self->sck_closed = 1; DEBUG((" out rdp_tcp_recv error connection dropped")); return 1; } else { s->end += rcvd; len -= rcvd; } } return 0; } /*****************************************************************************/ /* returns error */ int APP_CC rdp_tcp_send(struct rdp_tcp* self, struct stream* s) { int len; int total; int sent; if (self->sck_closed) { DEBUG((" out rdp_tcp_send error sck closed")); return 1; } len = s->end - s->data; DEBUG((" in rdp_tcp_send gota send %d bytes on sck %d", len, self->sck)); total = 0; while (total < len) { sent = g_tcp_send(self->sck, s->data + total, len - total, 0); if (sent == -1) { if (g_tcp_last_error_would_block(self->sck)) { g_tcp_can_send(self->sck, 10); } else { self->sck_closed = 1; DEBUG((" out rdp_tcp_send error unknown")); return 1; } } else if (sent == 0) { self->sck_closed = 1; DEBUG((" out rdp_tcp_send error connection dropped")); return 1; } else { total = total + sent; } } return 0; } /*****************************************************************************/ /* returns error */ int APP_CC rdp_tcp_connect(struct rdp_tcp* self, char* ip, char* port) { DEBUG((" in rdp_tcp_connect ip %s port %s", ip, port)); self->sck = g_tcp_socket(); if (g_tcp_connect(self->sck, ip, port) == 0) { g_tcp_set_non_blocking(self->sck); } else { DEBUG((" out rdp_tcp_connect error g_tcp_connect failed")); return 1; } DEBUG((" out rdp_tcp_connect")); return 0; } /*****************************************************************************/ /* returns error */ int APP_CC rdp_tcp_disconnect(struct rdp_tcp* self) { if (self->sck != 0) { g_tcp_close(self->sck); } self->sck = 0; return 0; } xrdp-0.6.0/readme.txt000066400000000000000000000022571203155130500144710ustar00rootroot00000000000000 xrdp 0.6.0 Credits This project is very much dependent on rdesktop and the work of Matt Chapman and the rdesktop team members, of which I'm a member Mark from up 19.9 was the first to work with rdp server code. Tested with linux on i386, x64, sparc, and ppc. I've got it compiling and working in windows with borland free tools. Non of the sesman or Xserver stuff works in windows of course. xrdp directory is the main server code vnc directory is a simple vnc client module for xrdp sesman directory is a session manager for xrdp that uses Xvnc for the Xserver libxrdp directory is a static library needed by xrdp rdp is an rdp client module for connecting to another rdp server xup is a module used to connect to an rdp specific X11 server Xserver is the files needed to build an rdp specific X11 server COPYING is the licence file design.txt is an attempt to expain the project design prog_std.txt is an attemp to explain the programming standard used since version 0.5.0 we switch to autotool to build xrdp to build and install change to the xrdp directory and run ./bootstrap ./configure make then as root make install see file-loc.txt to see what files are installed where Jay xrdp-0.6.0/sesman/000077500000000000000000000000001203155130500137535ustar00rootroot00000000000000xrdp-0.6.0/sesman/Doxyfile000066400000000000000000000202141203155130500154600ustar00rootroot00000000000000# Doxyfile 1.4.4 #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- PROJECT_NAME = xrdp/sesman PROJECT_NUMBER = 0.2.0 OUTPUT_DIRECTORY = ../docs/sesman CREATE_SUBDIRS = NO OUTPUT_LANGUAGE = English USE_WINDOWS_ENCODING = NO BRIEF_MEMBER_DESC = YES REPEAT_BRIEF = NO ABBREVIATE_BRIEF = ALWAYS_DETAILED_SEC = NO INLINE_INHERITED_MEMB = NO FULL_PATH_NAMES = YES STRIP_FROM_PATH = STRIP_FROM_INC_PATH = SHORT_NAMES = NO JAVADOC_AUTOBRIEF = NO MULTILINE_CPP_IS_BRIEF = NO DETAILS_AT_TOP = NO INHERIT_DOCS = YES DISTRIBUTE_GROUP_DOC = NO SEPARATE_MEMBER_PAGES = NO TAB_SIZE = 8 ALIASES = OPTIMIZE_OUTPUT_FOR_C = YES OPTIMIZE_OUTPUT_JAVA = NO SUBGROUPING = YES #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- EXTRACT_ALL = YES EXTRACT_PRIVATE = NO EXTRACT_STATIC = NO EXTRACT_LOCAL_CLASSES = NO EXTRACT_LOCAL_METHODS = NO HIDE_UNDOC_MEMBERS = YES HIDE_UNDOC_CLASSES = YES HIDE_FRIEND_COMPOUNDS = NO HIDE_IN_BODY_DOCS = NO INTERNAL_DOCS = NO CASE_SENSE_NAMES = YES HIDE_SCOPE_NAMES = NO SHOW_INCLUDE_FILES = YES INLINE_INFO = YES SORT_MEMBER_DOCS = YES SORT_BRIEF_DOCS = NO SORT_BY_SCOPE_NAME = NO GENERATE_TODOLIST = YES GENERATE_TESTLIST = YES GENERATE_BUGLIST = YES GENERATE_DEPRECATEDLIST= YES ENABLED_SECTIONS = MAX_INITIALIZER_LINES = 30 SHOW_USED_FILES = YES SHOW_DIRECTORIES = YES FILE_VERSION_FILTER = #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- QUIET = NO WARNINGS = YES WARN_IF_UNDOCUMENTED = YES WARN_IF_DOC_ERROR = YES WARN_NO_PARAMDOC = NO WARN_FORMAT = "$file:$line: $text" WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- INPUT = FILE_PATTERNS = RECURSIVE = NO EXCLUDE = EXCLUDE_SYMLINKS = NO EXCLUDE_PATTERNS = EXAMPLE_PATH = EXAMPLE_PATTERNS = EXAMPLE_RECURSIVE = NO IMAGE_PATH = INPUT_FILTER = FILTER_PATTERNS = FILTER_SOURCE_FILES = NO #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- SOURCE_BROWSER = YES INLINE_SOURCES = NO STRIP_CODE_COMMENTS = YES REFERENCED_BY_RELATION = YES REFERENCES_RELATION = YES USE_HTAGS = NO VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- ALPHABETICAL_INDEX = YES COLS_IN_ALPHA_INDEX = 5 IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- GENERATE_HTML = YES HTML_OUTPUT = html HTML_FILE_EXTENSION = .html HTML_HEADER = HTML_FOOTER = HTML_STYLESHEET = HTML_ALIGN_MEMBERS = YES GENERATE_HTMLHELP = NO CHM_FILE = HHC_LOCATION = GENERATE_CHI = NO BINARY_TOC = NO TOC_EXPAND = NO DISABLE_INDEX = NO ENUM_VALUES_PER_LINE = 4 GENERATE_TREEVIEW = NO TREEVIEW_WIDTH = 250 #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- GENERATE_LATEX = NO LATEX_OUTPUT = latex LATEX_CMD_NAME = latex MAKEINDEX_CMD_NAME = makeindex COMPACT_LATEX = NO PAPER_TYPE = a4wide EXTRA_PACKAGES = LATEX_HEADER = PDF_HYPERLINKS = NO USE_PDFLATEX = NO LATEX_BATCHMODE = NO LATEX_HIDE_INDICES = NO #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- GENERATE_RTF = NO RTF_OUTPUT = rtf COMPACT_RTF = NO RTF_HYPERLINKS = NO RTF_STYLESHEET_FILE = RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- GENERATE_MAN = NO MAN_OUTPUT = man MAN_EXTENSION = .3 MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- GENERATE_XML = NO XML_OUTPUT = xml XML_SCHEMA = XML_DTD = XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- GENERATE_PERLMOD = NO PERLMOD_LATEX = NO PERLMOD_PRETTY = YES PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- ENABLE_PREPROCESSING = YES MACRO_EXPANSION = NO EXPAND_ONLY_PREDEF = NO SEARCH_INCLUDES = NO INCLUDE_PATH = INCLUDE_FILE_PATTERNS = PREDEFINED = EXPAND_AS_DEFINED = SKIP_FUNCTION_MACROS = NO #--------------------------------------------------------------------------- # Configuration::additions related to external references #--------------------------------------------------------------------------- TAGFILES = GENERATE_TAGFILE = ALLEXTERNALS = NO EXTERNAL_GROUPS = YES PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- CLASS_DIAGRAMS = NO HIDE_UNDOC_RELATIONS = YES HAVE_DOT = NO CLASS_GRAPH = YES COLLABORATION_GRAPH = YES GROUP_GRAPHS = YES UML_LOOK = NO TEMPLATE_RELATIONS = NO INCLUDE_GRAPH = YES INCLUDED_BY_GRAPH = YES CALL_GRAPH = NO GRAPHICAL_HIERARCHY = YES DIRECTORY_GRAPH = YES DOT_IMAGE_FORMAT = png DOT_PATH = DOTFILE_DIRS = MAX_DOT_GRAPH_WIDTH = 1024 MAX_DOT_GRAPH_HEIGHT = 1024 MAX_DOT_GRAPH_DEPTH = 0 DOT_TRANSPARENT = NO DOT_MULTI_TARGETS = NO GENERATE_LEGEND = YES DOT_CLEANUP = YES #--------------------------------------------------------------------------- # Configuration::additions related to the search engine #--------------------------------------------------------------------------- SEARCHENGINE = NO xrdp-0.6.0/sesman/Makefile.am000066400000000000000000000023751203155130500160160ustar00rootroot00000000000000EXTRA_DIST = sesman.ini startwm.sh sesman.h access.h auth.h config.h env.h lock.h scp.h scp_v0.h scp_v1.h scp_v1_mng.h session.h sig.h thread.h AM_CFLAGS = \ -DXRDP_CFG_PATH=\"${sysconfdir}/xrdp\" \ -DXRDP_SBIN_PATH=\"${sbindir}\" \ -DXRDP_SHARE_PATH=\"${datadir}/xrdp\" \ -DXRDP_PID_PATH=\"${localstatedir}/run\" INCLUDES = \ -I$(top_srcdir)/common \ -I$(top_srcdir)/sesman/libscp if SESMAN_NOPAM AUTH_C = verify_user.c AUTH_LIB = -lcrypt else if SESMAN_PAMUSERPASS AUTH_C = verify_user_pam_userpass.c AUTH_LIB = -lpam -lpam_userpass else if SESMAN_KERBEROS AUTH_C = verify_user_kerberos.c AUTH_LIB = -lkrb5 else AUTH_C = verify_user_pam.c AUTH_LIB = -lpam endif endif endif sbin_PROGRAMS = \ xrdp-sesman xrdp_sesman_SOURCES = \ scp.c \ scp_v0.c \ scp_v1.c \ scp_v1_mng.c \ sesman.c \ session.c \ sig.c \ thread.c \ lock.c \ access.c \ config.c \ env.c \ $(AUTH_C) xrdp_sesman_LDADD = \ $(top_srcdir)/common/libcommon.la \ $(top_srcdir)/sesman/libscp/libscp.la \ $(AUTH_LIB) \ -lpthread sesmansysconfdir=$(sysconfdir)/xrdp sesmansysconf_DATA = \ sesman.ini \ startwm.sh SUBDIRS = \ libscp \ tools \ sessvc \ chansrv # must be tab below install-data-hook: chmod 755 $(DESTDIR)$(sysconfdir)/xrdp/startwm.sh xrdp-0.6.0/sesman/access.c000066400000000000000000000062751203155130500153720ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2005-2010 */ /** * * @file access.c * @brief User access control code * @author Simone Fedele * */ #include "sesman.h" extern struct config_sesman* g_cfg; /* in sesman.c */ /******************************************************************************/ int DEFAULT_CC access_login_allowed(char* user) { int gid; int ok; if ((0 == g_strncmp(user, "root", 5)) && (0 == g_cfg->sec.allow_root)) { log_message(&(g_cfg->log), LOG_LEVEL_WARNING, "ROOT login attempted, but root login is disabled"); return 0; } if (0 == g_cfg->sec.ts_users_enable) { LOG_DBG(&(g_cfg->log), "Terminal Server Users group is disabled, allowing authentication", 1); return 1; } if (0 != g_getuser_info(user, &gid, 0, 0, 0, 0)) { log_message(&(g_cfg->log), LOG_LEVEL_ERROR, "Cannot read user info! - login denied"); return 0; } if (g_cfg->sec.ts_users == gid) { LOG_DBG(&(g_cfg->log), "ts_users is user's primary group"); return 1; } if (0 != g_check_user_in_group(user, g_cfg->sec.ts_users, &ok)) { log_message(&(g_cfg->log), LOG_LEVEL_ERROR, "Cannot read group info! - login denied"); return 0; } if (ok) { return 1; } log_message(&(g_cfg->log), LOG_LEVEL_INFO, "login denied for user %s", user); return 0; } /******************************************************************************/ int DEFAULT_CC access_login_mng_allowed(char* user) { int gid; int ok; if ((0 == g_strncmp(user, "root", 5)) && (0 == g_cfg->sec.allow_root)) { log_message(&(g_cfg->log), LOG_LEVEL_WARNING, "[MNG] ROOT login attempted, but root login is disabled"); return 0; } if (0 == g_cfg->sec.ts_admins_enable) { LOG_DBG(&(g_cfg->log), "[MNG] Terminal Server Admin group is disabled, allowing authentication", 1); return 1; } if (0 != g_getuser_info(user, &gid, 0, 0, 0, 0)) { log_message(&(g_cfg->log), LOG_LEVEL_ERROR, "[MNG] Cannot read user info! - login denied"); return 0; } if (g_cfg->sec.ts_admins == gid) { LOG_DBG(&(g_cfg->log), "[MNG] ts_users is user's primary group"); return 1; } if (0 != g_check_user_in_group(user, g_cfg->sec.ts_admins, &ok)) { log_message(&(g_cfg->log), LOG_LEVEL_ERROR, "[MNG] Cannot read group info! - login denied"); return 0; } if (ok) { return 1; } log_message(&(g_cfg->log), LOG_LEVEL_INFO, "[MNG] login denied for user %s", user); return 0; } xrdp-0.6.0/sesman/access.h000066400000000000000000000025351203155130500153720ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2005-2010 */ /** * * @file access.h * @brief User access control definitions * @author Simone Fedele * */ #ifndef ACCESS_H #define ACCESS_H /** * * @brief Checks if the user is allowed to access the terminal server * @param user the user to check * @return 0 if access is denied, !=0 if allowed * */ int DEFAULT_CC access_login_allowed(char* user); /** * * @brief Checks if the user is allowed to access the terminal server for management * @param user the user to check * @return 0 if access is denied, !=0 if allowed * */ int DEFAULT_CC access_login_mng_allowed(char* user); #endif xrdp-0.6.0/sesman/auth.h000066400000000000000000000037521203155130500150740ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2005-2010 */ /** * * @file auth.h * @brief User authentication definitions * @author Jay Sorg * */ #ifndef AUTH_H #define AUTH_H /** * * @brief Validates user's password * @param user user's login name * @param pass user's password * @return 0 on success, 1 on failure * */ long DEFAULT_CC auth_userpass(char* user, char* pass); /** * * @brief FIXME * @param in_val * @param in_display * @return 0 on success, 1 on failure * */ int DEFAULT_CC auth_start_session(long in_val, int in_display); /** * * @brief FIXME * @param in_val * @return 0 on success, 1 on failure * */ int DEFAULT_CC auth_end(long in_val); /** * * @brief FIXME * @param in_val * @return 0 on success, 1 on failure * */ int DEFAULT_CC auth_set_env(long in_val); #define AUTH_PWD_CHG_OK 0 #define AUTH_PWD_CHG_CHANGE 1 #define AUTH_PWD_CHG_CHANGE_MANDATORY 2 #define AUTH_PWD_CHG_NOT_NOW 3 #define AUTH_PWD_CHG_ERROR 4 /** * * @brief FIXME * @param in_val * @return 0 on success, 1 on failure * */ int DEFAULT_CC auth_check_pwd_chg(char* user); /** * * @brief FIXME * @param in_val * @return 0 on success, 1 on failure * */ int DEFAULT_CC auth_change_pwd(char* user, char* newpwd); #endif xrdp-0.6.0/sesman/chansrv/000077500000000000000000000000001203155130500154175ustar00rootroot00000000000000xrdp-0.6.0/sesman/chansrv/Makefile.am000066400000000000000000000007471203155130500174630ustar00rootroot00000000000000EXTRA_DIST = chansrv.h clipboard.h devredir.h sound.h AM_CFLAGS = \ -DXRDP_CFG_PATH=\"${sysconfdir}/xrdp\" \ -DXRDP_SBIN_PATH=\"${sbindir}\" \ -DXRDP_SHARE_PATH=\"${datadir}/xrdp\" \ -DXRDP_PID_PATH=\"${localstatedir}/run\" INCLUDES = \ -I$(top_srcdir)/common sbin_PROGRAMS = \ xrdp-chansrv xrdp_chansrv_SOURCES = \ chansrv.c \ sound.c \ clipboard.c \ devredir.c xrdp_chansrv_LDADD = \ -L/usr/X11R6/lib \ $(top_srcdir)/common/libcommon.la \ -lX11 -lXfixes xrdp-0.6.0/sesman/chansrv/chansrv.c000066400000000000000000000414331203155130500172340ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2009-2010 */ #include "arch.h" #include "os_calls.h" #include "thread_calls.h" #include "trans.h" #include "chansrv.h" #include "defines.h" #include "sound.h" #include "clipboard.h" #include "devredir.h" #include "list.h" #include "file.h" #include "file_loc.h" static struct trans* g_lis_trans = 0; static struct trans* g_con_trans = 0; static struct chan_item g_chan_items[32]; static int g_num_chan_items = 0; static int g_cliprdr_index = -1; static int g_rdpsnd_index = -1; static int g_rdpdr_index = -1; static tbus g_term_event = 0; static tbus g_thread_done_event = 0; static int g_use_unix_socket = 0; int g_display_num = 0; int g_cliprdr_chan_id = -1; /* cliprdr */ int g_rdpsnd_chan_id = -1; /* rdpsnd */ int g_rdpdr_chan_id = -1; /* rdpdr */ /*****************************************************************************/ /* returns error */ int APP_CC send_channel_data(int chan_id, char* data, int size) { struct stream * s = (struct stream *)NULL; int chan_flags = 0; int total_size = 0; int sent = 0; int rv = 0; s = trans_get_out_s(g_con_trans, 8192); if (s == 0) { return 1; } rv = 0; sent = 0; total_size = size; while (sent < total_size) { size = MIN(1600, total_size - sent); chan_flags = 0; if (sent == 0) { chan_flags |= 1; /* first */ } if (size + sent == total_size) { chan_flags |= 2; /* last */ } out_uint32_le(s, 0); /* version */ out_uint32_le(s, 8 + 8 + 2 + 2 + 2 + 4 + size); /* size */ out_uint32_le(s, 8); /* msg id */ out_uint32_le(s, 8 + 2 + 2 + 2 + 4 + size); /* size */ out_uint16_le(s, chan_id); out_uint16_le(s, chan_flags); out_uint16_le(s, size); out_uint32_le(s, total_size); out_uint8a(s, data + sent, size); s_mark_end(s); rv = trans_force_write(g_con_trans); if (rv != 0) { break; } sent += size; s = trans_get_out_s(g_con_trans, 8192); } return rv; } /*****************************************************************************/ /* returns error */ static int APP_CC send_init_response_message(void) { struct stream * s = (struct stream *)NULL; LOG(1, ("send_init_response_message:")); s = trans_get_out_s(g_con_trans, 8192); if (s == 0) { return 1; } out_uint32_le(s, 0); /* version */ out_uint32_le(s, 8 + 8); /* size */ out_uint32_le(s, 2); /* msg id */ out_uint32_le(s, 8); /* size */ s_mark_end(s); return trans_force_write(g_con_trans); } /*****************************************************************************/ /* returns error */ static int APP_CC send_channel_setup_response_message(void) { struct stream * s = (struct stream *)NULL; LOG(10, ("send_channel_setup_response_message:")); s = trans_get_out_s(g_con_trans, 8192); if (s == 0) { return 1; } out_uint32_le(s, 0); /* version */ out_uint32_le(s, 8 + 8); /* size */ out_uint32_le(s, 4); /* msg id */ out_uint32_le(s, 8); /* size */ s_mark_end(s); return trans_force_write(g_con_trans); } /*****************************************************************************/ /* returns error */ static int APP_CC send_channel_data_response_message(void) { struct stream * s = (struct stream *)NULL; LOG(10, ("send_channel_data_response_message:")); s = trans_get_out_s(g_con_trans, 8192); if (s == 0) { return 1; } out_uint32_le(s, 0); /* version */ out_uint32_le(s, 8 + 8); /* size */ out_uint32_le(s, 6); /* msg id */ out_uint32_le(s, 8); /* size */ s_mark_end(s); return trans_force_write(g_con_trans); } /*****************************************************************************/ /* returns error */ static int APP_CC process_message_init(struct stream* s) { LOG(10, ("process_message_init:")); return send_init_response_message(); } /*****************************************************************************/ /* returns error */ static int APP_CC process_message_channel_setup(struct stream* s) { int num_chans = 0; int index = 0; int rv = 0; struct chan_item* ci = (struct chan_item *)NULL; g_num_chan_items = 0; g_cliprdr_index = -1; g_rdpsnd_index = -1; g_rdpdr_index = -1; g_cliprdr_chan_id = -1; g_rdpsnd_chan_id = -1; g_rdpdr_chan_id = -1; LOG(10, ("process_message_channel_setup:")); in_uint16_le(s, num_chans); LOG(10, ("process_message_channel_setup: num_chans %d", num_chans)); for (index = 0; index < num_chans; index++) { ci = &(g_chan_items[g_num_chan_items]); g_memset(ci->name, 0, sizeof(ci->name)); in_uint8a(s, ci->name, 8); in_uint16_le(s, ci->id); in_uint16_le(s, ci->flags); LOG(10, ("process_message_channel_setup: chan name '%s' " "id %d flags %8.8x", ci->name, ci->id, ci->flags)); if (g_strcasecmp(ci->name, "cliprdr") == 0) { g_cliprdr_index = g_num_chan_items; g_cliprdr_chan_id = ci->id; } else if (g_strcasecmp(ci->name, "rdpsnd") == 0) { g_rdpsnd_index = g_num_chan_items; g_rdpsnd_chan_id = ci->id; } else if (g_strcasecmp(ci->name, "rdpdr") == 0) { g_rdpdr_index = g_num_chan_items; g_rdpdr_chan_id = ci->id; } g_num_chan_items++; } rv = send_channel_setup_response_message(); if (g_cliprdr_index >= 0) { clipboard_init(); } if (g_rdpsnd_index >= 0) { sound_init(); } if (g_rdpdr_index >= 0) { dev_redir_init(); } return rv; } /*****************************************************************************/ /* returns error */ static int APP_CC process_message_channel_data(struct stream* s) { int chan_id = 0; int chan_flags = 0; int rv = 0; int length = 0; int total_length = 0; in_uint16_le(s, chan_id); in_uint16_le(s, chan_flags); in_uint16_le(s, length); in_uint32_le(s, total_length); LOG(10, ("process_message_channel_data: chan_id %d " "chan_flags %d", chan_id, chan_flags)); rv = send_channel_data_response_message(); if (rv == 0) { if (chan_id == g_cliprdr_chan_id) { rv = clipboard_data_in(s, chan_id, chan_flags, length, total_length); } else if (chan_id == g_rdpsnd_chan_id) { rv = sound_data_in(s, chan_id, chan_flags, length, total_length); } else if (chan_id == g_rdpdr_chan_id) { rv = dev_redir_data_in(s, chan_id, chan_flags, length, total_length); } } return rv; } /*****************************************************************************/ /* returns error */ static int APP_CC process_message_channel_data_response(struct stream* s) { LOG(10, ("process_message_channel_data_response:")); return 0; } /*****************************************************************************/ /* returns error */ static int APP_CC process_message(void) { struct stream * s = (struct stream *)NULL; int size = 0; int id = 0; int rv = 0; char* next_msg = (char *)NULL; if (g_con_trans == 0) { return 1; } s = trans_get_in_s(g_con_trans); if (s == 0) { return 1; } rv = 0; while (s_check_rem(s, 8)) { next_msg = s->p; in_uint32_le(s, id); in_uint32_le(s, size); next_msg += size; switch (id) { case 1: /* init */ rv = process_message_init(s); break; case 3: /* channel setup */ rv = process_message_channel_setup(s); break; case 5: /* channel data */ rv = process_message_channel_data(s); break; case 7: /* channel data response */ rv = process_message_channel_data_response(s); break; default: LOG(0, ("process_message: error in process_message " "unknown msg %d", id)); break; } if (rv != 0) { break; } else { s->p = next_msg; } } return rv; } /*****************************************************************************/ /* returns error */ int DEFAULT_CC my_trans_data_in(struct trans* trans) { struct stream * s = (struct stream *)NULL; int id = 0; int size = 0; int error = 0; if (trans == 0) { return 0; } if (trans != g_con_trans) { return 1; } LOG(10, ("my_trans_data_in:")); s = trans_get_in_s(trans); in_uint32_le(s, id); in_uint32_le(s, size); error = trans_force_read(trans, size - 8); if (error == 0) { /* here, the entire message block is read in, process it */ error = process_message(); } return error; } /*****************************************************************************/ int DEFAULT_CC my_trans_conn_in(struct trans* trans, struct trans* new_trans) { if (trans == 0) { return 1; } if (trans != g_lis_trans) { return 1; } if (g_con_trans != 0) /* if already set, error */ { return 1; } if (new_trans == 0) { return 1; } LOG(10, ("my_trans_conn_in:")); g_con_trans = new_trans; g_con_trans->trans_data_in = my_trans_data_in; g_con_trans->header_size = 8; /* stop listening */ trans_delete(g_lis_trans); g_lis_trans = 0; return 0; } /*****************************************************************************/ static int APP_CC setup_listen(void) { char port[256]; int error = 0; if (g_lis_trans != 0) { trans_delete(g_lis_trans); } if (g_use_unix_socket) { g_lis_trans = trans_create(2, 8192, 8192); g_snprintf(port, 255, "/tmp/.xrdp/xrdp_chansrv_socket_%d", 7200 + g_display_num); } else { g_lis_trans = trans_create(1, 8192, 8192); g_snprintf(port, 255, "%d", 7200 + g_display_num); } g_lis_trans->trans_conn_in = my_trans_conn_in; error = trans_listen(g_lis_trans, port); if (error != 0) { LOG(0, ("setup_listen: trans_listen failed for port %s", port)); return 1; } return 0; } /*****************************************************************************/ THREAD_RV THREAD_CC channel_thread_loop(void* in_val) { tbus objs[32]; int num_objs = 0; int timeout = 0; int error = 0; THREAD_RV rv = 0; LOG(1, ("channel_thread_loop: thread start")); rv = 0; error = setup_listen(); if (error == 0) { timeout = -1; num_objs = 0; objs[num_objs] = g_term_event; num_objs++; trans_get_wait_objs(g_lis_trans, objs, &num_objs, &timeout); while (g_obj_wait(objs, num_objs, 0, 0, timeout) == 0) { if (g_is_wait_obj_set(g_term_event)) { LOG(0, ("channel_thread_loop: g_term_event set")); clipboard_deinit(); sound_deinit(); dev_redir_deinit(); break; } if (g_lis_trans != 0) { if (trans_check_wait_objs(g_lis_trans) != 0) { LOG(0, ("channel_thread_loop: trans_check_wait_objs error")); } } if (g_con_trans != 0) { if (trans_check_wait_objs(g_con_trans) != 0) { LOG(0, ("channel_thread_loop: " "trans_check_wait_objs error resetting")); clipboard_deinit(); sound_deinit(); dev_redir_deinit(); /* delete g_con_trans */ trans_delete(g_con_trans); g_con_trans = 0; /* create new listener */ error = setup_listen(); if (error != 0) { break; } } } clipboard_check_wait_objs(); sound_check_wait_objs(); dev_redir_check_wait_objs(); timeout = -1; num_objs = 0; objs[num_objs] = g_term_event; num_objs++; trans_get_wait_objs(g_lis_trans, objs, &num_objs, &timeout); trans_get_wait_objs(g_con_trans, objs, &num_objs, &timeout); clipboard_get_wait_objs(objs, &num_objs, &timeout); sound_get_wait_objs(objs, &num_objs, &timeout); dev_redir_get_wait_objs(objs, &num_objs, &timeout); } } trans_delete(g_lis_trans); g_lis_trans = 0; trans_delete(g_con_trans); g_con_trans = 0; LOG(0, ("channel_thread_loop: thread stop")); g_set_wait_obj(g_thread_done_event); return rv; } /*****************************************************************************/ void DEFAULT_CC term_signal_handler(int sig) { LOG(1, ("term_signal_handler: got signal %d", sig)); g_set_wait_obj(g_term_event); } /*****************************************************************************/ void DEFAULT_CC nil_signal_handler(int sig) { LOG(1, ("nil_signal_handler: got signal %d", sig)); g_set_wait_obj(g_term_event); } /*****************************************************************************/ static int APP_CC get_display_num_from_display(char * display_text) { int index = 0; int mode = 0; int host_index = 0; int disp_index = 0; int scre_index = 0; char host[256] = ""; char disp[256] = ""; char scre[256] = ""; g_memset(host,0,256); g_memset(disp,0,256); g_memset(scre,0,256); index = 0; host_index = 0; disp_index = 0; scre_index = 0; mode = 0; while (display_text[index] != 0) { if (display_text[index] == ':') { mode = 1; } else if (display_text[index] == '.') { mode = 2; } else if (mode == 0) { host[host_index] = display_text[index]; host_index++; } else if (mode == 1) { disp[disp_index] = display_text[index]; disp_index++; } else if (mode == 2) { scre[scre_index] = display_text[index]; scre_index++; } index++; } host[host_index] = 0; disp[disp_index] = 0; scre[scre_index] = 0; g_display_num = g_atoi(disp); return 0; } /*****************************************************************************/ int APP_CC main_cleanup(void) { g_delete_wait_obj(g_term_event); g_delete_wait_obj(g_thread_done_event); g_deinit(); /* os_calls */ return 0; } /*****************************************************************************/ static int APP_CC read_ini(void) { char filename[256] = ""; struct list* names = (struct list *)NULL; struct list* values = (struct list *)NULL; char* name = (char *)NULL; char* value = (char *)NULL; int index = 0; g_memset(filename,0,(sizeof(char)*256)); names = list_create(); names->auto_free = 1; values = list_create(); values->auto_free = 1; g_use_unix_socket = 0; g_snprintf(filename, 255, "%s/sesman.ini", XRDP_CFG_PATH); if (file_by_name_read_section(filename, "Globals", names, values) == 0) { for (index = 0; index < names->count; index++) { name = (char*)list_get_item(names, index); value = (char*)list_get_item(values, index); if (g_strcasecmp(name, "ListenAddress") == 0) { if (g_strcasecmp(value, "127.0.0.1") == 0) { g_use_unix_socket = 1; } } } } list_delete(names); list_delete(values); return 0; } /*****************************************************************************/ int DEFAULT_CC main(int argc, char** argv) { int pid = 0; char text[256] = ""; char* display_text = (char *)NULL; g_init("xrdp-chansrv"); /* os_calls */ read_ini(); pid = g_getpid(); LOG(1, ("main: app started pid %d(0x%8.8x)", pid, pid)); /* set up signal handler */ g_signal_kill(term_signal_handler); /* SIGKILL */ g_signal_terminate(term_signal_handler); /* SIGTERM */ g_signal_user_interrupt(term_signal_handler); /* SIGINT */ g_signal_pipe(nil_signal_handler); /* SIGPIPE */ display_text = g_getenv("DISPLAY"); LOG(1, ("main: DISPLAY env var set to %s", display_text)); get_display_num_from_display(display_text); if (g_display_num == 0) { LOG(0, ("main: error, display is zero")); return 1; } LOG(1, ("main: using DISPLAY %d", g_display_num)); g_snprintf(text, 255, "xrdp_chansrv_%8.8x_main_term", pid); g_term_event = g_create_wait_obj(text); g_snprintf(text, 255, "xrdp_chansrv_%8.8x_thread_done", pid); g_thread_done_event = g_create_wait_obj(text); tc_thread_create(channel_thread_loop, 0); while (g_term_event > 0 && !g_is_wait_obj_set(g_term_event)) { if (g_obj_wait(&g_term_event, 1, 0, 0, 0) != 0) { LOG(0, ("main: error, g_obj_wait failed")); break; } } while (g_thread_done_event > 0 && !g_is_wait_obj_set(g_thread_done_event)) { /* wait for thread to exit */ if (g_obj_wait(&g_thread_done_event, 1, 0, 0, 0) != 0) { LOG(0, ("main: error, g_obj_wait failed")); break; } } /* cleanup */ main_cleanup(); LOG(1, ("main: app exiting pid %d(0x%8.8x)", pid, pid)); g_deinit(); return 0; } xrdp-0.6.0/sesman/chansrv/chansrv.h000066400000000000000000000006441203155130500172400ustar00rootroot00000000000000 #if !defined(CHANSRV_H) #define CHANSRV_H #include "arch.h" #include "parse.h" struct chan_item { int id; int flags; char name[16]; }; int APP_CC send_channel_data(int chan_id, char* data, int size); int APP_CC main_cleanup(void); #define LOG_LEVEL 5 #define LOG(_a, _params) \ { \ if (_a < LOG_LEVEL) \ { \ g_write("xrdp-chansrv [%10.10u]: ", g_time3()); \ g_writeln _params ; \ } \ } #endif xrdp-0.6.0/sesman/chansrv/clipboard.c000066400000000000000000001003161203155130500175230ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2009-2010 for help see http://tronche.com/gui/x/icccm/sec-2.html#s-2 .../kde/kdebase/workspace/klipper/clipboardpoll.cpp */ #include #include #include #include "arch.h" #include "parse.h" #include "os_calls.h" #include "chansrv.h" static Atom g_clipboard_atom = 0; static Atom g_clip_property_atom = 0; static Atom g_timestamp_atom = 0; static Atom g_multiple_atom = 0; static Atom g_targets_atom = 0; static Atom g_primary_atom = 0; static Atom g_secondary_atom = 0; static Atom g_get_time_atom = 0; static Atom g_utf8_atom = 0; static int g_x_socket = 0; static tbus g_x_wait_obj = 0; static int g_clip_up = 0; static Window g_wnd = 0; static Screen* g_screen = 0; static int g_screen_num = 0; static int g_xfixes_event_base = 0; static int g_last_clip_size = 0; static char* g_last_clip_data = 0; static Atom g_last_clip_type = 0; static int g_got_selection = 0; /* boolean */ static Time g_selection_time = 0; static struct stream* g_ins = 0; static XSelectionRequestEvent g_selection_request_event[16]; static int g_selection_request_event_count = 0; static char* g_data_in = 0; static int g_data_in_size = 0; static int g_data_in_time = 0; static int g_data_in_up_to_date = 0; static int g_got_format_announce = 0; static int g_waiting_for_data_response = 0; static int g_waiting_for_data_response_time = 0; static Display* g_display = 0; extern int g_cliprdr_chan_id; /* in chansrv.c */ /*****************************************************************************/ int DEFAULT_CC clipboard_error_handler(Display* dis, XErrorEvent* xer) { char text[256]; XGetErrorText(dis, xer->error_code, text, 255); LOG(1, ("error [%s]", text)); return 0; } /*****************************************************************************/ /* The X server had an internal error. This is the last function called. Do any cleanup that needs to be done on exit, like removing temporary files. Don't worry about memory leaks */ int DEFAULT_CC clipboard_fatal_handler(Display* dis) { LOG(1, ("fatal error, exiting")); main_cleanup(); return 0; } /*****************************************************************************/ /* this is one way to get the current time from the x server */ static Time APP_CC clipboard_get_server_time(void) { XEvent xevent; /* append nothing */ XChangeProperty(g_display, g_wnd, g_get_time_atom, XA_STRING, 8, PropModeAppend, "", 0); /* wait for PropertyNotify */ do { XMaskEvent(g_display, PropertyChangeMask, &xevent); } while (xevent.type != PropertyNotify); return xevent.xproperty.time; } /*****************************************************************************/ /* returns time in miliseconds this is like g_time2 in os_calls, but not miliseconds since machine was up, something else this is a time value similar to what the xserver uses */ static int APP_CC clipboard_get_local_time(void) { return g_time3(); } /*****************************************************************************/ /* returns error */ int APP_CC clipboard_init(void) { struct stream* s; int size; int rv; int input_mask; int dummy; int ver_maj; int ver_min; Status st; LOG(5, ("xrdp-chansrv: in clipboard_init")); if (g_clip_up) { return 0; } clipboard_deinit(); rv = 0; /* setting the error handlers can cause problem when shutting down chansrv on some xlibs */ //XSetErrorHandler(clipboard_error_handler); //XSetIOErrorHandler(clipboard_fatal_handler); g_display = XOpenDisplay(0); if (g_display == 0) { LOG(0, ("clipboard_init: XOpenDisplay failed")); rv = 1; } if (rv == 0) { g_x_socket = XConnectionNumber(g_display); if (g_x_socket == 0) { LOG(0, ("clipboard_init: XConnectionNumber failed")); rv = 2; } g_x_wait_obj = g_create_wait_obj_from_socket(g_x_socket, 0); } if (rv == 0) { g_clipboard_atom = XInternAtom(g_display, "CLIPBOARD", False); if (g_clipboard_atom == None) { LOG(0, ("clipboard_init: XInternAtom failed")); rv = 3; } } if (rv == 0) { if (!XFixesQueryExtension(g_display, &g_xfixes_event_base, &dummy)) { LOG(0, ("clipboard_init: no xfixes")); rv = 5; } } if (rv == 0) { LOG(0, ("clipboard_init: g_xfixes_event_base %d", g_xfixes_event_base)); st = XFixesQueryVersion(g_display, &ver_maj, &ver_min); LOG(0, ("clipboard_init st %d, maj %d min %d", st, ver_maj, ver_min)); g_screen_num = DefaultScreen(g_display); g_screen = ScreenOfDisplay(g_display, g_screen_num); g_clip_property_atom = XInternAtom(g_display, "XRDP_CLIP_PROPERTY_ATOM", False); g_get_time_atom = XInternAtom(g_display, "XRDP_GET_TIME_ATOM", False); g_timestamp_atom = XInternAtom(g_display, "TIMESTAMP", False); g_targets_atom = XInternAtom(g_display, "TARGETS", False); g_multiple_atom = XInternAtom(g_display, "MULTIPLE", False); g_primary_atom = XInternAtom(g_display, "PRIMARY", False); g_secondary_atom = XInternAtom(g_display, "SECONDARY", False); g_utf8_atom = XInternAtom(g_display, "UTF8_STRING", False); g_wnd = XCreateSimpleWindow(g_display, RootWindowOfScreen(g_screen), 0, 0, 4, 4, 0, 0, 0); input_mask = StructureNotifyMask | PropertyChangeMask; XSelectInput(g_display, g_wnd, input_mask); //XMapWindow(g_display, g_wnd); XFixesSelectSelectionInput(g_display, g_wnd, g_clipboard_atom, XFixesSetSelectionOwnerNotifyMask | XFixesSelectionWindowDestroyNotifyMask | XFixesSelectionClientCloseNotifyMask); } if (rv == 0) { make_stream(s); init_stream(s, 8192); out_uint16_le(s, 1); /* CLIPRDR_CONNECT */ out_uint16_le(s, 0); /* status */ out_uint32_le(s, 0); /* length */ out_uint32_le(s, 0); /* extra 4 bytes ? */ s_mark_end(s); size = (int)(s->end - s->data); LOG(5, ("clipboard_init: data out, sending " "CLIPRDR_CONNECT (clip_msg_id = 1)")); rv = send_channel_data(g_cliprdr_chan_id, s->data, size); if (rv != 0) { LOG(0, ("clipboard_init: send_channel_data failed " "rv = %d", rv)); rv = 4; } free_stream(s); } if (rv == 0) { g_clip_up = 1; make_stream(g_ins); init_stream(g_ins, 8192); } else { LOG(0, ("xrdp-chansrv: clipboard_init: error on exit")); } return rv; } /*****************************************************************************/ int APP_CC clipboard_deinit(void) { if (g_x_wait_obj != 0) { g_delete_wait_obj_from_socket(g_x_wait_obj); g_x_wait_obj = 0; } if (g_wnd != 0) { XDestroyWindow(g_display, g_wnd); g_wnd = 0; } g_x_socket = 0; g_free(g_last_clip_data); g_last_clip_data = 0; g_last_clip_size = 0; free_stream(g_ins); g_ins = 0; if (g_display != 0) { XCloseDisplay(g_display); g_display = 0; } g_clip_up = 0; return 0; } /*****************************************************************************/ static int APP_CC clipboard_send_data_request(void) { struct stream* s; int size; int rv; int num_chars; LOG(5, ("clipboard_send_data_request:")); if (!g_got_format_announce) { LOG(0, ("clipboard_send_data_request: error, no format announce")); return 0; } g_got_format_announce = 0; make_stream(s); init_stream(s, 8192); out_uint16_le(s, 4); /* CLIPRDR_DATA_REQUEST */ out_uint16_le(s, 0); /* status */ out_uint32_le(s, 4); /* length */ out_uint32_le(s, 0x0d); s_mark_end(s); size = (int)(s->end - s->data); LOG(5, ("clipboard_send_data_request: data out, sending " "CLIPRDR_DATA_REQUEST (clip_msg_id = 4)")); rv = send_channel_data(g_cliprdr_chan_id, s->data, size); free_stream(s); return rv; } /*****************************************************************************/ static int APP_CC clipboard_send_format_ack(void) { struct stream* s; int size; int rv; make_stream(s); init_stream(s, 8192); out_uint16_le(s, 3); /* CLIPRDR_FORMAT_ACK */ out_uint16_le(s, 1); /* status */ out_uint32_le(s, 0); /* length */ out_uint32_le(s, 0); /* extra 4 bytes ? */ s_mark_end(s); size = (int)(s->end - s->data); LOG(5, ("clipboard_send_format_ack: data out, sending " "CLIPRDR_FORMAT_ACK (clip_msg_id = 3)")); rv = send_channel_data(g_cliprdr_chan_id, s->data, size); free_stream(s); return rv; } /*****************************************************************************/ static int APP_CC clipboard_send_format_announce(void) { struct stream* s; int size; int rv; make_stream(s); init_stream(s, 8192); out_uint16_le(s, 2); /* CLIPRDR_FORMAT_ANNOUNCE */ out_uint16_le(s, 0); /* status */ out_uint32_le(s, 0x90); /* length */ out_uint32_le(s, 0x0d); /* extra 4 bytes ? */ out_uint8s(s, 0x90); s_mark_end(s); size = (int)(s->end - s->data); LOG(5, ("clipboard_send_format_announce: data out, sending " "CLIPRDR_FORMAT_ANNOUNCE (clip_msg_id = 2)")); rv = send_channel_data(g_cliprdr_chan_id, s->data, size); free_stream(s); return rv; } /*****************************************************************************/ /* returns number of bytes written */ static int APP_CC clipboard_out_unicode(struct stream* s, char* text, int num_chars) { int index; int lnum_chars; twchar* ltext; if ((num_chars < 1) || (text == 0)) { return 0; } lnum_chars = g_mbstowcs(0, text, num_chars); if (lnum_chars < 0) { return 0; } ltext = g_malloc((num_chars + 1) * sizeof(twchar), 1); g_mbstowcs(ltext, text, num_chars); index = 0; while (index < num_chars) { out_uint16_le(s, ltext[index]); index++; } g_free(ltext); return index * 2; } /*****************************************************************************/ static int APP_CC clipboard_send_data_response(void) { struct stream* s; int size; int rv; int num_chars; LOG(10, ("clipboard_send_data_response:")); num_chars = 0; if (g_last_clip_data != 0) { if ((g_last_clip_type == XA_STRING) || (g_last_clip_type == g_utf8_atom)) { num_chars = g_mbstowcs(0, g_last_clip_data, 0); if (num_chars < 0) { LOG(0, ("clipboard_send_data_response: bad string")); num_chars = 0; } } } LOG(10, ("clipboard_send_data_response: g_last_clip_size %d " "num_chars %d", g_last_clip_size, num_chars)); make_stream(s); init_stream(s, 64 + num_chars * 2); out_uint16_le(s, 5); /* CLIPRDR_DATA_RESPONSE */ out_uint16_le(s, 1); /* status */ out_uint32_le(s, num_chars * 2 + 2); /* length */ if (clipboard_out_unicode(s, g_last_clip_data, num_chars) != num_chars * 2) { LOG(0, ("clipboard_send_data_response: error " "clipboard_out_unicode didn't write right number of bytes")); } out_uint16_le(s, 0); /* nil for string */ out_uint32_le(s, 0); s_mark_end(s); size = (int)(s->end - s->data); LOG(5, ("clipboard_send_data_response: data out, sending " "CLIPRDR_DATA_RESPONSE (clip_msg_id = 5) size %d num_chars %d", size, num_chars)); rv = send_channel_data(g_cliprdr_chan_id, s->data, size); free_stream(s); return rv; } /*****************************************************************************/ static int APP_CC clipboard_set_selection_owner(void) { Window owner; g_selection_time = clipboard_get_server_time(); XSetSelectionOwner(g_display, g_clipboard_atom, g_wnd, g_selection_time); owner = XGetSelectionOwner(g_display, g_clipboard_atom); if (owner != g_wnd) { g_got_selection = 0; return 1; } g_got_selection = 1; return 0; } /*****************************************************************************/ static int APP_CC clipboard_provide_selection(XSelectionRequestEvent* req, Atom type, int format, char* data, int length) { XEvent xev; XChangeProperty(g_display, req->requestor, req->property, type, format, PropModeReplace, (tui8*)data, length); g_memset(&xev, 0, sizeof(xev)); xev.xselection.type = SelectionNotify; xev.xselection.send_event = True; xev.xselection.display = req->display; xev.xselection.requestor = req->requestor; xev.xselection.selection = req->selection; xev.xselection.target = req->target; xev.xselection.property = req->property; xev.xselection.time = req->time; XSendEvent(g_display, req->requestor, False, NoEventMask, &xev); return 0; } /*****************************************************************************/ static int APP_CC clipboard_refuse_selection(XSelectionRequestEvent* req) { XEvent xev; g_memset(&xev, 0, sizeof(xev)); xev.xselection.type = SelectionNotify; xev.xselection.send_event = True; xev.xselection.display = req->display; xev.xselection.requestor = req->requestor; xev.xselection.selection = req->selection; xev.xselection.target = req->target; xev.xselection.property = None; xev.xselection.time = req->time; XSendEvent(g_display, req->requestor, False, NoEventMask, &xev); return 0; } /*****************************************************************************/ static int APP_CC clipboard_process_format_announce(struct stream* s, int clip_msg_status, int clip_msg_len) { Window owner; LOG(5, ("clipboard_process_format_announce: CLIPRDR_FORMAT_ANNOUNCE")); //g_hexdump(s->p, s->end - s->p); clipboard_send_format_ack(); g_got_format_announce = 1; g_data_in_up_to_date = 0; if (clipboard_set_selection_owner() != 0) { LOG(0, ("clipboard_process_format_announce: XSetSelectionOwner failed")); } return 0; } /*****************************************************************************/ static int APP_CC clipboard_prcoess_format_ack(struct stream* s, int clip_msg_status, int clip_msg_len) { LOG(5, ("clipboard_prcoess_format_ack: CLIPRDR_FORMAT_ACK")); //g_hexdump(s->p, s->end - s->p); return 0; } /*****************************************************************************/ static int APP_CC clipboard_process_data_request(struct stream* s, int clip_msg_status, int clip_msg_len) { LOG(5, ("clipboard_process_data_request: CLIPRDR_DATA_REQUEST")); //g_hexdump(s->p, s->end - s->p); clipboard_send_data_response(); return 0; } /*****************************************************************************/ static int APP_CC clipboard_process_data_response(struct stream* s, int clip_msg_status, int clip_msg_len) { XEvent xev; XSelectionRequestEvent* lxev; twchar* wtext; twchar wchr; int len; int index; int wtext_size; int data_in_len; LOG(5, ("clipboard_process_data_response: CLIPRDR_DATA_RESPONSE")); g_waiting_for_data_response = 0; len = (int)(s->end - s->p); if (len < 1) { return 0; } //g_hexdump(s->p, len); wtext = (twchar*)g_malloc(((len / 2) + 1) * sizeof(twchar), 0); if (wtext == 0) { return 0; } index = 0; while (s_check(s)) { in_uint16_le(s, wchr); wtext[index] = wchr; if (wchr == 0) { break; } index++; } wtext[index] = 0; g_free(g_data_in); g_data_in = 0; g_data_in_size = 0; g_data_in_time = 0; len = g_wcstombs(0, wtext, 0); if (len >= 0) { g_data_in = (char*)g_malloc(len + 16, 0); if (g_data_in == 0) { g_free(wtext); return 0; } g_data_in_size = len; g_wcstombs(g_data_in, wtext, len + 1); g_data_in_time = clipboard_get_local_time(); g_data_in_up_to_date = 1; } if (g_data_in != 0) { data_in_len = g_strlen(g_data_in); for (index = 0; index < g_selection_request_event_count; index++) { lxev = &(g_selection_request_event[index]); clipboard_provide_selection(lxev, lxev->target, 8, g_data_in, data_in_len); LOG(5, ("clipboard_process_data_response: requestor %d data_in_len %d", lxev->requestor, data_in_len)); } } g_selection_request_event_count = 0; g_free(wtext); return 0; } /*****************************************************************************/ int APP_CC clipboard_data_in(struct stream* s, int chan_id, int chan_flags, int length, int total_length) { int clip_msg_id; int clip_msg_len; int clip_msg_status; int rv; struct stream* ls; LOG(10, ("clipboard_data_in: chan_is %d " "chan_flags %d length %d total_length %d", chan_id, chan_flags, length, total_length)); if ((chan_flags & 3) == 3) { ls = s; } else { if (chan_flags & 1) { init_stream(g_ins, total_length); } in_uint8a(s, g_ins->end, length); g_ins->end += length; if ((chan_flags & 2) == 0) { return 0; } ls = g_ins; } in_uint16_le(ls, clip_msg_id); in_uint16_le(ls, clip_msg_status); in_uint32_le(ls, clip_msg_len); LOG(10, ("clipboard_data_in: clip_msg_id %d " "clip_msg_status %d clip_msg_len %d", clip_msg_id, clip_msg_status, clip_msg_len)); rv = 0; switch (clip_msg_id) { case 2: /* CLIPRDR_FORMAT_ANNOUNCE */ rv = clipboard_process_format_announce(ls, clip_msg_status, clip_msg_len); break; case 3: /* CLIPRDR_FORMAT_ACK */ rv = clipboard_prcoess_format_ack(ls, clip_msg_status, clip_msg_len); break; case 4: /* CLIPRDR_DATA_REQUEST */ rv = clipboard_process_data_request(ls, clip_msg_status, clip_msg_len); break; case 5: /* CLIPRDR_DATA_RESPONSE */ rv = clipboard_process_data_response(ls, clip_msg_status, clip_msg_len); break; default: LOG(0, ("clipboard_data_in: unknown clip_msg_id %d", clip_msg_id)); break; } XFlush(g_display); return rv; } /*****************************************************************************/ /* this happens when a new app copies something to the clipboard 'CLIPBOARD' Atom typedef struct { int type; unsigned long serial; Bool send_event; Display *display; Window window; int subtype; Window owner; Atom selection; Time timestamp; Time selection_timestamp; } XFixesSelectionNotifyEvent; */ static int APP_CC clipboard_event_selection_owner_notify(XEvent* xevent) { XFixesSelectionNotifyEvent* lxevent; lxevent = (XFixesSelectionNotifyEvent*)xevent; LOG(5, ("clipboard_event_selection_owner_notify: " "window %d subtype %d owner %d g_wnd %d", lxevent->window, lxevent->subtype, lxevent->owner, g_wnd)); if (lxevent->owner == g_wnd) { LOG(5, ("clipboard_event_selection_owner_notify: skipping, " "onwer == g_wnd")); g_got_selection = 1; return 0; } g_got_selection = 0; XConvertSelection(g_display, g_clipboard_atom, g_targets_atom, g_clip_property_atom, g_wnd, lxevent->timestamp); return 0; } /*****************************************************************************/ /* returns error get a window property from wnd */ static int APP_CC clipboard_get_window_property(Window wnd, Atom prop, Atom* type, int* fmt, int* n_items, char** xdata, int* xdata_size) { int lfmt; int lxdata_size; unsigned long ln_items; unsigned long llen_after; tui8* lxdata; Atom ltype; lxdata = 0; ltype = 0; XGetWindowProperty(g_display, g_wnd, prop, 0, 0, 0, AnyPropertyType, <ype, &lfmt, &ln_items, &llen_after, &lxdata); XFree(lxdata); if (ltype == 0) { /* XGetWindowProperty failed */ return 1; } if (llen_after < 1) { /* no data, ok */ return 0; } lxdata = 0; ltype = 0; XGetWindowProperty(g_display, g_wnd, prop, 0, (llen_after + 3) / 4, 0, AnyPropertyType, <ype, &lfmt, &ln_items, &llen_after, &lxdata); if (ltype == 0) { /* XGetWindowProperty failed */ XFree(lxdata); return 1; } lxdata_size = (lfmt / 8) * ln_items; if (lxdata_size < 1) { /* should not happen */ XFree(lxdata); return 2; } if (llen_after > 0) { /* should not happen */ XFree(lxdata); return 3; } if (xdata != 0) { *xdata = (char*)g_malloc(lxdata_size, 0); g_memcpy(*xdata, lxdata, lxdata_size); } XFree(lxdata); if (xdata_size != 0) { *xdata_size = lxdata_size; } if (fmt != 0) { *fmt = (int)lfmt; } if (n_items != 0) { *n_items = (int)ln_items; } if (type != 0) { *type = ltype; } return 0; } /*****************************************************************************/ /* returns error process the SelectionNotify X event, uses XSelectionEvent typedef struct { int type; // SelectionNotify unsigned long serial; // # of last request processed by server Bool send_event; // true if this came from a SendEvent request Display *display; // Display the event was read from Window requestor; Atom selection; Atom target; Atom property; // atom or None Time time; } XSelectionEvent; */ static int APP_CC clipboard_event_selection_notify(XEvent* xevent) { XSelectionEvent* lxevent; char* data; int data_size; int n_items; int fmt; int rv; int index; int convert_to_string; int convert_to_utf8; int send_format_announce; int atom; int* atoms; Atom type; LOG(5, ("clipboard_event_selection_notify:")); convert_to_string = 0; convert_to_utf8 = 0; send_format_announce = 0; rv = 0; data = 0; type = 0; lxevent = (XSelectionEvent*)xevent; if (lxevent->property == None) { LOG(0, ("clipboard_event_selection_notify: clip could " "not be converted")); rv = 1; } if (rv == 0) { rv = clipboard_get_window_property(lxevent->requestor, lxevent->property, &type, &fmt, &n_items, &data, &data_size); if (rv != 0) { LOG(0, ("clipboard_event_selection_notify: " "clipboard_get_window_property failed error %d", rv)); } XDeleteProperty(g_display, lxevent->requestor, lxevent->property); } if (rv == 0) { if (lxevent->selection == g_clipboard_atom) { if (lxevent->target == g_targets_atom) { if ((type == XA_ATOM) && (fmt == 32)) { atoms = (int*)data; for (index = 0; index < n_items; index++) { atom = atoms[index]; LOG(5, ("clipboard_event_selection_notify: %d %s %d", atom, XGetAtomName(g_display, atom), XA_STRING)); if (atom == g_utf8_atom) { convert_to_utf8 = 1; } else if (atom == XA_STRING) { convert_to_string = 1; } } } else { LOG(0, ("clipboard_event_selection_notify: error, target is " "'TARGETS' and type[%d] or fmt[%d] not right, should be " "type[%d], fmt[%d]", type, fmt, XA_ATOM, 32)); } } else if (lxevent->target == g_utf8_atom) { LOG(5, ("clipboard_event_selection_notify: UTF8_STRING data_size %d", data_size)); g_free(g_last_clip_data); g_last_clip_size = data_size; g_last_clip_data = g_malloc(g_last_clip_size + 1, 0); g_last_clip_type = g_utf8_atom; g_memcpy(g_last_clip_data, data, g_last_clip_size); g_last_clip_data[g_last_clip_size] = 0; send_format_announce = 1; } else if (lxevent->target == XA_STRING) { LOG(5, ("clipboard_event_selection_notify: XA_STRING data_size %d", data_size)); g_free(g_last_clip_data); g_last_clip_size = data_size; g_last_clip_data = g_malloc(g_last_clip_size + 1, 0); g_last_clip_type = XA_STRING; g_memcpy(g_last_clip_data, data, g_last_clip_size); g_last_clip_data[g_last_clip_size] = 0; send_format_announce = 1; } else { LOG(0, ("clipboard_event_selection_notify: unknown target")); } } else { LOG(0, ("clipboard_event_selection_notify: unknown selection")); } } if (convert_to_utf8) { XConvertSelection(g_display, g_clipboard_atom, g_utf8_atom, g_clip_property_atom, g_wnd, lxevent->time); } else if (convert_to_string) { XConvertSelection(g_display, g_clipboard_atom, XA_STRING, g_clip_property_atom, g_wnd, lxevent->time); } if (send_format_announce) { if (clipboard_send_format_announce() != 0) { rv = 4; } } g_free(data); return rv; } /*****************************************************************************/ /* returns error process the SelectionRequest X event, uses XSelectionRequestEvent typedef struct { int type; // SelectionRequest unsigned long serial; // # of last request processed by server Bool send_event; // true if this came from a SendEvent request Display *display; // Display the event was read from Window owner; Window requestor; Atom selection; Atom target; Atom property; Time time; } XSelectionRequestEvent; */ static int APP_CC clipboard_event_selection_request(XEvent* xevent) { XEvent xev; XSelectionRequestEvent* lxev; tui32 ui32[8]; Atom type; int fmt; int n_items; int xdata_size; char* xdata; lxev = (XSelectionRequestEvent*)xevent; LOG(5, ("clipboard_event_selection_request: g_wnd %d, " ".requestor %d .owner %d .selection %d '%s' .target %d .property %d", g_wnd, lxev->requestor, lxev->owner, lxev->selection, XGetAtomName(g_display, lxev->selection), lxev->target, lxev->property)); if (lxev->property == None) { LOG(5, ("clipboard_event_selection_request: lxev->property is None")); } else if (lxev->target == g_targets_atom) { /* requestor is asking what the selection can be converted to */ LOG(5, ("clipboard_event_selection_request: g_targets_atom")); ui32[0] = g_targets_atom; ui32[1] = g_timestamp_atom; ui32[2] = g_multiple_atom; ui32[3] = XA_STRING; ui32[4] = g_utf8_atom; return clipboard_provide_selection(lxev, XA_ATOM, 32, (char*)ui32, 5); } else if (lxev->target == g_timestamp_atom) { /* requestor is asking the time I got the selection */ LOG(5, ("clipboard_event_selection_request: g_timestamp_atom")); ui32[0] = g_selection_time; return clipboard_provide_selection(lxev, XA_INTEGER, 32, (char*)ui32, 1); } else if (lxev->target == g_multiple_atom) { /* target, property pairs */ LOG(5, ("clipboard_event_selection_request: g_multiple_atom")); if (clipboard_get_window_property(xev.xselection.requestor, xev.xselection.property, &type, &fmt, &n_items, &xdata, &xdata_size) == 0) { LOG(5, ("clipboard_event_selection_request: g_multiple_atom " "n_items %d", n_items)); /* todo */ g_free(xdata); } } else if ((lxev->target == XA_STRING) || (lxev->target == g_utf8_atom)) { LOG(5, ("clipboard_event_selection_request: %s", XGetAtomName(g_display, lxev->target))); if (g_data_in_up_to_date) { return clipboard_provide_selection(lxev, lxev->target, 8, g_data_in, g_strlen(g_data_in)); } if (g_selection_request_event_count > 10) { LOG(0, ("clipboard_event_selection_request: error, too many requests")); } else { g_memcpy(&(g_selection_request_event[g_selection_request_event_count]), lxev, sizeof(g_selection_request_event[0])); if (g_selection_request_event_count == 0) { clipboard_send_data_request(); g_waiting_for_data_response = 1; g_waiting_for_data_response_time = clipboard_get_local_time(); } g_selection_request_event_count++; return 0; } } else { LOG(0, ("clipboard_event_selection_request: unknown " "target %s", XGetAtomName(g_display, lxev->target))); } clipboard_refuse_selection(lxev); return 0; } /*****************************************************************************/ /* returns error process the SelectionClear X event, uses XSelectionClearEvent typedef struct { int type; // SelectionClear unsigned long serial; // # of last request processed by server Bool send_event; // true if this came from a SendEvent request Display *display; // Display the event was read from Window window; Atom selection; Time time; } XSelectionClearEvent; */ static int APP_CC clipboard_event_selection_clear(XEvent* xevent) { LOG(5, ("clipboard_event_selection_clear:")); return 0; } /*****************************************************************************/ /* returns error typedef struct { int type; // PropertyNotify unsigned long serial; // # of last request processed by server Bool send_event; // true if this came from a SendEvent request Display *display; // Display the event was read from Window window; Atom atom; Time time; int state; // PropertyNewValue or PropertyDelete } XPropertyEvent; */ static int APP_CC clipboard_event_property_notify(XEvent* xevent) { LOG(10, ("clipboard_check_wait_objs: PropertyNotify .window %d " ".state %d .atom %d", xevent->xproperty.window, xevent->xproperty.state, xevent->xproperty.atom)); return 0; } /*****************************************************************************/ /* returns error this is called to get any wait objects for the main loop timeout can be nil */ int APP_CC clipboard_get_wait_objs(tbus* objs, int* count, int* timeout) { int lcount; if ((!g_clip_up) || (objs == 0) || (count == 0)) { return 0; } lcount = *count; objs[lcount] = g_x_wait_obj; lcount++; *count = lcount; return 0; } /*****************************************************************************/ int APP_CC clipboard_check_wait_objs(void) { XEvent xevent; int time_diff; if (!g_clip_up) { return 0; } if (g_is_wait_obj_set(g_x_wait_obj)) { if (XPending(g_display) < 1) { /* something is wrong, should not get here */ LOG(0, ("clipboard_check_wait_objs: sck closed")); return 0; } if (g_waiting_for_data_response) { time_diff = clipboard_get_local_time() - g_waiting_for_data_response_time; if (time_diff > 1000) { LOG(0, ("clipboard_check_wait_objs: warning, waiting for " "data response too long")); } } while (XPending(g_display) > 0) { XNextEvent(g_display, &xevent); switch (xevent.type) { case SelectionNotify: clipboard_event_selection_notify(&xevent); break; case SelectionRequest: clipboard_event_selection_request(&xevent); break; case SelectionClear: clipboard_event_selection_clear(&xevent); break; case MappingNotify: break; case PropertyNotify: clipboard_event_property_notify(&xevent); break; default: if (xevent.type == g_xfixes_event_base + XFixesSetSelectionOwnerNotify) { clipboard_event_selection_owner_notify(&xevent); break; } LOG(0, ("clipboard_check_wait_objs unknown type %d", xevent.type)); break; } } } return 0; } xrdp-0.6.0/sesman/chansrv/clipboard.h000066400000000000000000000006251203155130500175320ustar00rootroot00000000000000 #if !defined(CLIPBOARD_H) #define CLIPBOARD_H #include "arch.h" #include "parse.h" int APP_CC clipboard_init(void); int APP_CC clipboard_deinit(void); int APP_CC clipboard_data_in(struct stream* s, int chan_id, int chan_flags, int length, int total_length); int APP_CC clipboard_get_wait_objs(tbus* objs, int* count, int* timeout); int APP_CC clipboard_check_wait_objs(void); #endif xrdp-0.6.0/sesman/chansrv/devredir.c000066400000000000000000000032161203155130500173710ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2009-2010 */ #include "arch.h" #include "parse.h" #include "os_calls.h" extern int g_rdpdr_chan_id; /* in chansrv.c */ /*****************************************************************************/ int APP_CC dev_redir_init(void) { return 0; } /*****************************************************************************/ int APP_CC dev_redir_deinit(void) { return 0; } /*****************************************************************************/ int APP_CC dev_redir_data_in(struct stream* s, int chan_id, int chan_flags, int length, int total_length) { return 0; } /*****************************************************************************/ int APP_CC dev_redir_get_wait_objs(tbus* objs, int* count, int* timeout) { return 0; } /*****************************************************************************/ int APP_CC dev_redir_check_wait_objs(void) { return 0; } xrdp-0.6.0/sesman/chansrv/devredir.h000066400000000000000000000006231203155130500173750ustar00rootroot00000000000000 #if !defined(DEVREDIR_H) #define DEVREDIR_H #include "arch.h" #include "parse.h" int APP_CC dev_redir_init(void); int APP_CC dev_redir_deinit(void); int APP_CC dev_redir_data_in(struct stream* s, int chan_id, int chan_flags, int length, int total_length); int APP_CC dev_redir_get_wait_objs(tbus* objs, int* count, int* timeout); int APP_CC dev_redir_check_wait_objs(void); #endif xrdp-0.6.0/sesman/chansrv/sound.c000066400000000000000000000031671203155130500167220ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2009-2010 */ #include "arch.h" #include "parse.h" #include "os_calls.h" extern int g_rdpsnd_chan_id; /* in chansrv.c */ /*****************************************************************************/ int APP_CC sound_init(void) { return 0; } /*****************************************************************************/ int APP_CC sound_deinit(void) { return 0; } /*****************************************************************************/ int APP_CC sound_data_in(struct stream* s, int chan_id, int chan_flags, int length, int total_length) { return 0; } /*****************************************************************************/ int APP_CC sound_get_wait_objs(tbus* objs, int* count, int* timeout) { return 0; } /*****************************************************************************/ int APP_CC sound_check_wait_objs(void) { return 0; } xrdp-0.6.0/sesman/chansrv/sound.h000066400000000000000000000005651203155130500167260ustar00rootroot00000000000000 #if !defined(SOUND_H) #define SOUND_H #include "arch.h" #include "parse.h" int APP_CC sound_init(void); int APP_CC sound_deinit(void); int APP_CC sound_data_in(struct stream* s, int chan_id, int chan_flags, int length, int total_length); int APP_CC sound_get_wait_objs(tbus* objs, int* count, int* timeout); int APP_CC sound_check_wait_objs(void); #endif xrdp-0.6.0/sesman/config.c000066400000000000000000000274341203155130500153760ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2005-2010 */ /** * * @file config.c * @brief User authentication code * @author Simone Fedele @< simo [at] esseemme [dot] org @> * */ #include "arch.h" #include "list.h" #include "file.h" #include "sesman.h" extern struct config_sesman* g_cfg; /* in sesman.c */ /******************************************************************************/ /** * * @brief Reads sesman configuration * @param s translates the strings "1", "true" and "yes" in 1 (true) and other strings in 0 * @return 0 on success, 1 on failure * */ static int APP_CC text2bool(char* s) { if (0 == g_strcasecmp(s, "1") || 0 == g_strcasecmp(s, "true") || 0 == g_strcasecmp(s, "yes")) { return 1; } return 0; } /******************************************************************************/ int DEFAULT_CC config_read(struct config_sesman* cfg) { int fd; struct list* sec; struct list* param_n; struct list* param_v; char cfg_file[256]; g_snprintf(cfg_file, 255, "%s/sesman.ini", XRDP_CFG_PATH); fd = g_file_open(cfg_file); if (-1 == fd) { if (g_cfg->log.fd >= 0) { /* logging is already active */ log_message(&(g_cfg->log), LOG_LEVEL_ALWAYS, "error opening %s in \ config_read", cfg_file); } else { g_printf("error opening %s in config_read", cfg_file); } return 1; } g_memset(cfg, 0, sizeof(struct config_sesman)); sec = list_create(); sec->auto_free = 1; file_read_sections(fd, sec); param_n = list_create(); param_n->auto_free = 1; param_v = list_create(); param_v->auto_free = 1; /* read global config */ config_read_globals(fd, cfg, param_n, param_v); /* read Xvnc/X11rdp parameter list */ config_read_vnc_params(fd, cfg, param_n, param_v); config_read_rdp_params(fd, cfg, param_n, param_v); /* read logging config */ config_read_logging(fd, &(cfg->log), param_n, param_v); /* read security config */ config_read_security(fd, &(cfg->sec), param_n, param_v); /* read session config */ config_read_sessions(fd, &(cfg->sess), param_n, param_v); /* cleanup */ list_delete(sec); list_delete(param_v); list_delete(param_n); g_file_close(fd); return 0; } /******************************************************************************/ int DEFAULT_CC config_read_globals(int file, struct config_sesman* cf, struct list* param_n, struct list* param_v) { int i; char* buf; list_clear(param_v); list_clear(param_n); /* resetting the struct */ cf->listen_address[0] = '\0'; cf->listen_port[0] = '\0'; cf->enable_user_wm = 0; cf->user_wm[0] = '\0'; cf->default_wm[0] = '\0'; cf->auth_file_path = 0; file_read_section(file, SESMAN_CFG_GLOBALS, param_n, param_v); for (i = 0; i < param_n->count; i++) { buf = (char*)list_get_item(param_n, i); if (0 == g_strcasecmp(buf, SESMAN_CFG_DEFWM)) { g_strncpy(cf->default_wm, (char*)list_get_item(param_v, i), 31); } else if (0 == g_strcasecmp(buf, SESMAN_CFG_USERWM)) { g_strncpy(cf->user_wm, (char*)list_get_item(param_v, i), 31); } else if (0 == g_strcasecmp(buf, SESMAN_CFG_ENABLE_USERWM)) { cf->enable_user_wm = text2bool((char*)list_get_item(param_v, i)); } else if (0 == g_strcasecmp(buf, SESMAN_CFG_PORT)) { g_strncpy(cf->listen_port, (char*)list_get_item(param_v, i), 15); } else if (0 == g_strcasecmp(buf, SESMAN_CFG_ADDRESS)) { g_strncpy(cf->listen_address, (char*)list_get_item(param_v, i), 31); } else if (0 == g_strcasecmp(buf, SESMAN_CFG_AUTH_FILE_PATH)) { cf->auth_file_path = g_strdup((char*)list_get_item(param_v, i)); } } /* checking for missing required parameters */ if ('\0' == cf->listen_address[0]) { g_strncpy(cf->listen_address, "0.0.0.0", 8); } if ('\0' == cf->listen_port[0]) { g_strncpy(cf->listen_port, "3350", 5); } if ('\0' == cf->user_wm[0]) { cf->enable_user_wm = 0; } if ('\0' == cf->default_wm[0]) { g_strncpy(cf->default_wm, "startwm.sh", 11); } /* showing read config */ g_printf("sesman config:\r\n"); g_printf("\tListenAddress: %s\r\n", cf->listen_address); g_printf("\tListenPort: %s\r\n", cf->listen_port); g_printf("\tEnableUserWindowManager: %i\r\n", cf->enable_user_wm); g_printf("\tUserWindowManager: %s\r\n", cf->user_wm); g_printf("\tDefaultWindowManager: %s\r\n", cf->default_wm); g_printf("\tAuthFilePath: %s\r\n", ((cf->auth_file_path) ? (cf->auth_file_path) : ("disabled"))); return 0; } /******************************************************************************/ int DEFAULT_CC config_read_logging(int file, struct log_config* lc, struct list* param_n, struct list* param_v) { int i; char* buf; list_clear(param_v); list_clear(param_n); /* setting defaults */ lc->program_name = g_strdup("sesman"); lc->log_file = 0; lc->fd = 0; lc->log_level = LOG_LEVEL_DEBUG; lc->enable_syslog = 0; lc->syslog_level = LOG_LEVEL_DEBUG; file_read_section(file, SESMAN_CFG_LOGGING, param_n, param_v); for (i = 0; i < param_n->count; i++) { buf = (char*)list_get_item(param_n, i); if (0 == g_strcasecmp(buf, SESMAN_CFG_LOG_FILE)) { lc->log_file = g_strdup((char*)list_get_item(param_v, i)); } if (0 == g_strcasecmp(buf, SESMAN_CFG_LOG_LEVEL)) { lc->log_level = log_text2level((char*)list_get_item(param_v, i)); } if (0 == g_strcasecmp(buf, SESMAN_CFG_LOG_ENABLE_SYSLOG)) { lc->enable_syslog = text2bool((char*)list_get_item(param_v, i)); } if (0 == g_strcasecmp(buf, SESMAN_CFG_LOG_SYSLOG_LEVEL)) { lc->syslog_level = log_text2level((char*)list_get_item(param_v, i)); } } if (0 == lc->log_file) { lc->log_file=g_strdup("./sesman.log"); } g_printf("logging configuration:\r\n"); g_printf("\tLogFile: %s\r\n",lc->log_file); g_printf("\tLogLevel: %i\r\n", lc->log_level); g_printf("\tEnableSyslog: %i\r\n", lc->enable_syslog); g_printf("\tSyslogLevel: %i\r\n", lc->syslog_level); return 0; } /******************************************************************************/ int DEFAULT_CC config_read_security(int file, struct config_security* sc, struct list* param_n, struct list* param_v) { int i; int gid; char* buf; list_clear(param_v); list_clear(param_n); /* setting defaults */ sc->allow_root = 0; sc->login_retry = 3; sc->ts_users_enable = 0; sc->ts_admins_enable = 0; file_read_section(file, SESMAN_CFG_SECURITY, param_n, param_v); for (i = 0; i < param_n->count; i++) { buf = (char*)list_get_item(param_n, i); if (0 == g_strcasecmp(buf, SESMAN_CFG_SEC_ALLOW_ROOT)) { sc->allow_root = text2bool((char*)list_get_item(param_v, i)); } if (0 == g_strcasecmp(buf, SESMAN_CFG_SEC_LOGIN_RETRY)) { sc->login_retry = g_atoi((char*)list_get_item(param_v, i)); } if (0 == g_strcasecmp(buf, SESMAN_CFG_SEC_USR_GROUP)) { if (g_getgroup_info((char*)list_get_item(param_v, i), &gid) == 0) { sc->ts_users_enable = 1; sc->ts_users = gid; } } if (0 == g_strcasecmp(buf, SESMAN_CFG_SEC_ADM_GROUP)) { if (g_getgroup_info((char*)list_get_item(param_v, i), &gid) == 0) { sc->ts_admins_enable = 1; sc->ts_admins = gid; } } } /* printing security config */ g_printf("security configuration:\r\n"); g_printf("\tAllowRootLogin: %i\r\n",sc->allow_root); g_printf("\tMaxLoginRetry: %i\r\n",sc->login_retry); if (sc->ts_users_enable) { g_printf("\tTSUsersGroup: %i\r\n", sc->ts_users); } else { g_printf("\tNo TSUsersGroup defined\r\n"); } if (sc->ts_admins_enable) { g_printf("\tTSAdminsGroup: %i\r\n", sc->ts_admins); } else { g_printf("\tNo TSAdminsGroup defined\r\n"); } return 0; } /******************************************************************************/ int DEFAULT_CC config_read_sessions(int file, struct config_sessions* se, struct list* param_n, struct list* param_v) { int i; char* buf; list_clear(param_v); list_clear(param_n); /* setting defaults */ se->x11_display_offset=10; se->max_sessions=0; se->max_idle_time=0; se->max_disc_time=0; se->kill_disconnected=0; file_read_section(file, SESMAN_CFG_SESSIONS, param_n, param_v); for (i = 0; i < param_n->count; i++) { buf = (char*)list_get_item(param_n, i); if (0 == g_strcasecmp(buf, SESMAN_CFG_X11DISPLAYOFFSET)) { se->x11_display_offset = g_atoi((char*)list_get_item(param_v, i)); } if (0 == g_strcasecmp(buf, SESMAN_CFG_SESS_MAX)) { se->max_sessions = g_atoi((char*)list_get_item(param_v, i)); } if (0 == g_strcasecmp(buf, SESMAN_CFG_SESS_KILL_DISC)) { se->kill_disconnected = text2bool((char*)list_get_item(param_v, i)); } if (0 == g_strcasecmp(buf, SESMAN_CFG_SESS_IDLE_LIMIT)) { se->max_idle_time=g_atoi((char*)list_get_item(param_v, i)); } if (0 == g_strcasecmp(buf, SESMAN_CFG_SESS_DISC_LIMIT)) { se->max_disc_time=g_atoi((char*)list_get_item(param_v, i)); } } /* printing security config */ g_printf("session configuration:\r\n"); g_printf("\tMaxSessions: %i\r\n", se->max_sessions); g_printf("\tX11DisplayOffset: %i\r\n", se->x11_display_offset); g_printf("\tKillDisconnected: %i\r\n", se->kill_disconnected); g_printf("\tIdleTimeLimit: %i\r\n", se->max_idle_time); g_printf("\tDisconnectedTimeLimit: %i\r\n", se->max_idle_time); return 0; } /******************************************************************************/ int DEFAULT_CC config_read_rdp_params(int file, struct config_sesman* cs, struct list* param_n, struct list* param_v) { int i; list_clear(param_v); list_clear(param_n); cs->rdp_params=list_create(); file_read_section(file, SESMAN_CFG_RDP_PARAMS, param_n, param_v); for (i = 0; i < param_n->count; i++) { list_add_item(cs->rdp_params, (long)g_strdup((char*)list_get_item(param_v, i))); } /* printing security config */ g_printf("X11rdp parameters:\r\n"); for (i = 0; i < cs->rdp_params->count; i++) { g_printf("\tParameter %02d %s\r\n", i, (char*)list_get_item(cs->rdp_params, i)); } return 0; } /******************************************************************************/ int DEFAULT_CC config_read_vnc_params(int file, struct config_sesman* cs, struct list* param_n, struct list* param_v) { int i; list_clear(param_v); list_clear(param_n); cs->vnc_params=list_create(); file_read_section(file, SESMAN_CFG_VNC_PARAMS, param_n, param_v); for (i = 0; i < param_n->count; i++) { list_add_item(cs->vnc_params, (long)g_strdup((char*)list_get_item(param_v, i))); } /* printing security config */ g_printf("Xvnc parameters:\r\n"); for (i = 0; i < cs->vnc_params->count; i++) { g_printf("\tParameter %02d %s\r\n", i, (char*)list_get_item(cs->vnc_params, i)); } return 0; } xrdp-0.6.0/sesman/config.h000066400000000000000000000170471203155130500154020ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2005-2010 */ /** * * @file config.h * @brief User authentication definitions * @author Simone Fedele @< simo [at] esseemme [dot] org @> * */ #ifndef CONFIG_H #define CONFIG_H #include "arch.h" #include "list.h" #include "log.h" #define SESMAN_CFG_GLOBALS "Globals" #define SESMAN_CFG_DEFWM "DefaultWindowManager" #define SESMAN_CFG_ADDRESS "ListenAddress" #define SESMAN_CFG_PORT "ListenPort" #define SESMAN_CFG_ENABLE_USERWM "EnableUserWindowManager" #define SESMAN_CFG_USERWM "UserWindowManager" #define SESMAN_CFG_X11DISPLAYOFFSET "X11DisplayOffset" #define SESMAN_CFG_MAX_SESSION "MaxSessions" #define SESMAN_CFG_AUTH_FILE_PATH "AuthFilePath" #define SESMAN_CFG_RDP_PARAMS "X11rdp" #define SESMAN_CFG_VNC_PARAMS "Xvnc" #define SESMAN_CFG_LOGGING "Logging" #define SESMAN_CFG_LOG_FILE "LogFile" #define SESMAN_CFG_LOG_LEVEL "LogLevel" #define SESMAN_CFG_LOG_ENABLE_SYSLOG "EnableSyslog" #define SESMAN_CFG_LOG_SYSLOG_LEVEL "SyslogLevel" #define SESMAN_CFG_SECURITY "Security" #define SESMAN_CFG_SEC_LOGIN_RETRY "MaxLoginRetry" #define SESMAN_CFG_SEC_ALLOW_ROOT "AllowRootLogin" #define SESMAN_CFG_SEC_USR_GROUP "TerminalServerUsers" #define SESMAN_CFG_SEC_ADM_GROUP "TerminalServerAdmins" #define SESMAN_CFG_SESSIONS "Sessions" #define SESMAN_CFG_SESS_MAX "MaxSessions" #define SESMAN_CFG_SESS_KILL_DISC "KillDisconnected" #define SESMAN_CFG_SESS_IDLE_LIMIT "IdleTimeLimit" #define SESMAN_CFG_SESS_DISC_LIMIT "DisconnectedTimeLimit" /** * * @struct config_security * @brief struct that contains sesman access control configuration * */ struct config_security { /** * @var allow_root * @brief allow root login on TS */ int allow_root; /** * @var login_retry * @brief maximum login attempts */ int login_retry; /** * @var ts_users * @brief Terminal Server Users group */ int ts_users_enable; int ts_users; /** * @var ts_admins * @brief Terminal Server Adminnistrators group */ int ts_admins_enable; int ts_admins; }; /** * * @struct config_sessions * @brief struct that contains sesman session handling configuration * */ struct config_sessions { /** * @var x11_display_offset * @brief X11 TCP port offset. default value: 10 */ int x11_display_offset; /** * @var max_sessions * @brief maximum number of allowed sessions. 0 for unlimited */ int max_sessions; /** * @var max_idle_time * @brief maximum idle time for each session */ int max_idle_time; /** * @var max_disc_time * @brief maximum disconnected time for each session */ int max_disc_time; /** * @var kill_disconnected * @brief enables automatic killing of disconnected session */ int kill_disconnected; }; /** * * @struct config_sesman * @brief struct that contains sesman configuration * * This struct contains all of sesman configuration parameters\n * Every parameter in [globals] is a member of this struct, other * sections options are embedded in this struct as member structures * */ struct config_sesman { /** * @var listen_address * @brief Listening address */ char listen_address[32]; /** * @var listen_port * @brief Listening port */ char listen_port[16]; /** * @var enable_user_wm * @brief Flag that enables user specific wm */ int enable_user_wm; /** * @var default_wm * @brief Default window manager */ char default_wm[32]; /** * @var user_wm * @brief Default window manager */ char user_wm[32]; /** * @var auth_file_path * @brief Auth file path */ char* auth_file_path; /** * @var vnc_params * @brief Xvnc additional parameter list */ struct list* vnc_params; /** * @var rdp_params * @brief X11rdp additional parameter list */ struct list* rdp_params; /** * @var log * @brief Log configuration struct */ struct log_config log; /** * @var sec * @brief Security configuration options struct */ struct config_security sec; /** * @var sess * @brief Session configuration options struct */ struct config_sessions sess; }; /** * * @brief Reads sesman configuration * @param cfg pointer to configuration object to be replaced * @return 0 on success, 1 on failure * */ int DEFAULT_CC config_read(struct config_sesman* cfg); /** * * @brief Reads sesman [global] configuration section * @param file configuration file descriptor * @param cf pointer to a config struct * @param param_n parameter name list * @param param_v parameter value list * @return 0 on success, 1 on failure * */ int DEFAULT_CC config_read_globals(int file, struct config_sesman* cf, struct list* param_n, struct list* param_v); /** * * @brief Reads sesman [logging] configuration section * @param file configuration file descriptor * @param lc pointer to a log_config struct * @param param_n parameter name list * @param param_v parameter value list * @return 0 on success, 1 on failure * */ int DEFAULT_CC config_read_logging(int file, struct log_config* lc, struct list* param_n, struct list* param_v); /** * * @brief Reads sesman [Security] configuration section * @param file configuration file descriptor * @param sc pointer to a config_security struct * @param param_n parameter name list * @param param_v parameter value list * @return 0 on success, 1 on failure * */ int DEFAULT_CC config_read_security(int file, struct config_security* sc, struct list* param_n, struct list* param_v); /** * * @brief Reads sesman [Sessions] configuration section * @param file configuration file descriptor * @param ss pointer to a config_sessions struct * @param param_n parameter name list * @param param_v parameter value list * @return 0 on success, 1 on failure * */ int DEFAULT_CC config_read_sessions(int file, struct config_sessions* ss, struct list* param_n, struct list* param_v); /** * * @brief Reads sesman [X11rdp] configuration section * @param file configuration file descriptor * @param cs pointer to a config_sesman struct * @param param_n parameter name list * @param param_v parameter value list * @return 0 on success, 1 on failure * */ int DEFAULT_CC config_read_rdp_params(int file, struct config_sesman* cs, struct list* param_n, struct list* param_v); /** * * @brief Reads sesman [Xvnc] configuration section * @param file configuration file descriptor * @param cs pointer to a config_sesman struct * @param param_n parameter name list * @param param_v parameter value list * @return 0 on success, 1 on failure * */ int DEFAULT_CC config_read_vnc_params(int file, struct config_sesman* cs, struct list* param_n, struct list* param_v); #endif xrdp-0.6.0/sesman/env.c000066400000000000000000000065621203155130500147200ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2005-2010 */ /** * * @file env.c * @brief User environment handling code * @author Jay Sorg * */ #include "sesman.h" #include "sys/types.h" #include "grp.h" extern unsigned char g_fixedkey[8]; /* in sesman.c */ extern struct config_sesman* g_cfg; /* in sesman.c */ /******************************************************************************/ int DEFAULT_CC env_check_password_file(char* filename, char* password) { char encryptedPasswd[16]; int fd; g_memset(encryptedPasswd, 0, 16); g_strncpy(encryptedPasswd, password, 8); rfbDesKey(g_fixedkey, 0); rfbDes((unsigned char*)encryptedPasswd, (unsigned char*)encryptedPasswd); fd = g_file_open(filename); if (fd == -1) { log_message(&(g_cfg->log), LOG_LEVEL_WARNING, "can't read vnc password file - %s", filename); return 1; } g_file_write(fd, encryptedPasswd, 8); g_file_close(fd); return 0; } /******************************************************************************/ int DEFAULT_CC env_set_user(char* username, char* passwd_file, int display) { int error; int pw_uid; int pw_gid; int uid; char pw_shell[256]; char pw_dir[256]; char pw_gecos[256]; char text[256]; error = g_getuser_info(username, &pw_gid, &pw_uid, pw_shell, pw_dir, pw_gecos); if (error == 0) { g_rm_temp_dir(); error = g_setgid(pw_gid); if (error == 0) { error = g_initgroups(username, pw_gid); } if (error == 0) { uid = pw_uid; error = g_setuid(uid); } g_mk_temp_dir(0); if (error == 0) { g_clearenv(); g_setenv("SHELL", pw_shell, 1); g_setenv("PATH", "/bin:/usr/bin:/usr/X11R6/bin:/usr/local/bin", 1); g_setenv("USER", username, 1); g_sprintf(text, "%d", uid); g_setenv("UID", text, 1); g_setenv("HOME", pw_dir, 1); g_set_current_dir(pw_dir); g_sprintf(text, ":%d.0", display); g_setenv("DISPLAY", text, 1); if (passwd_file != 0) { if (0 == g_cfg->auth_file_path) { /* if no auth_file_path is set, then we go for $HOME/.vnc/sesman_username_passwd */ g_mkdir(".vnc"); g_sprintf(passwd_file, "%s/.vnc/sesman_%s_passwd", pw_dir, username); } else { /* we use auth_file_path as requested */ g_sprintf(passwd_file, g_cfg->auth_file_path, username); } LOG_DBG(&(g_cfg->log), "pass file: %s", passwd_file); } } } else { log_message(&(g_cfg->log), LOG_LEVEL_ERROR, "error getting user info for user %s", username); } return error; } xrdp-0.6.0/sesman/env.h000066400000000000000000000027311203155130500147170ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2005-2010 */ /** * * @file env.h * @brief User environment handling code declarations * @author Jay Sorg * */ #ifndef ENV_H #define ENV_H /** * * @brief Creates vnc password file * @param filename VNC password file name * @param password The password to be encrypte * @return 0 on success, 1 on error * */ int DEFAULT_CC env_check_password_file(char* filename, char* password); /** * * @brief Sets user environment ($PATH, $HOME, $UID, and others) * @param username Username * @param passwd_file VNC password file * @param display The session display * @return 0 on success, g_getuser_info() error codes on error * */ int DEFAULT_CC env_set_user(char* username, char* passwd_file, int display); #endif xrdp-0.6.0/sesman/libscp/000077500000000000000000000000001203155130500152275ustar00rootroot00000000000000xrdp-0.6.0/sesman/libscp/Makefile.am000066400000000000000000000014531203155130500172660ustar00rootroot00000000000000EXTRA_DIST = libscp_connection.h libscp_commands.h libscp.h libscp_session.h libscp_types_mng.h libscp_v1c_mng.h libscp_vX.h libscp_commands_mng.h libscp_init.h libscp_tcp.h libscp_v0.h libscp_v1s.h libscp_lock.h \ libscp_types.h libscp_v1c.h libscp_v1s_mng.h AM_CFLAGS = \ -DXRDP_CFG_PATH=\"${sysconfdir}/xrdp\" \ -DXRDP_SBIN_PATH=\"${sbindir}\" \ -DXRDP_SHARE_PATH=\"${datadir}/xrdp\" \ -DXRDP_PID_PATH=\"${localstatedir}/run\" INCLUDES = \ -I$(top_srcdir)/common lib_LTLIBRARIES = \ libscp.la libscp_la_SOURCES = \ libscp_connection.c \ libscp_init.c \ libscp_lock.c \ libscp_session.c \ libscp_tcp.c \ libscp_v0.c \ libscp_v1c.c \ libscp_v1s.c \ libscp_v1c_mng.c \ libscp_v1s_mng.c \ libscp_vX.c libscp_la_LIBADD = \ $(top_srcdir)/common/libcommon.la \ -lpthread xrdp-0.6.0/sesman/libscp/libscp.h000066400000000000000000000024341203155130500166570ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2005-2010 */ /** * * @file libscp.h * @brief libscp main header * @author Simone Fedele * */ #ifndef LIBSCP_H #define LIBSCP_H #if defined(HAVE_CONFIG_H) #include "config_ac.h" #endif #include "libscp_types.h" #include "libscp_commands.h" #include "libscp_connection.h" #include "libscp_session.h" #include "libscp_init.h" #include "libscp_tcp.h" #include "libscp_lock.h" #include "libscp_vX.h" #include "libscp_v0.h" #include "libscp_v1s.h" #include "libscp_v1c.h" #include "libscp_v1s_mng.h" #include "libscp_v1c_mng.h" #endif xrdp-0.6.0/sesman/libscp/libscp_commands.h000066400000000000000000000020361203155130500205360ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2005-2010 */ /** * * @file libscp_commands.h * @brief libscp data types definitions * @author Simone Fedele * */ #ifndef LIBSCP_COMMANDS_H #define LIBSCP_COMMANDS_H #include "libscp_commands_mng.h" #define SCP_CMD_LOGIN 0x0001 #define SCP_CMD_CONN_ERROR 0xFFFF #endif xrdp-0.6.0/sesman/libscp/libscp_commands_mng.h000066400000000000000000000023301203155130500213740ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2005-2010 */ /** * * @file libscp_commands_mng.h * @brief libscp data types definitions * @author Simone Fedele * */ #ifndef LIBSCP_COMMANDS_MNG_H #define LIBSCP_COMMANDS_MNG_H #define SCP_CMD_MNG_LOGIN 0x0001 #define SCP_CMD_MNG_LOGIN_ALLOW 0x0002 #define SCP_CMD_MNG_LOGIN_DENY 0x0003 #define SCP_CMD_MNG_CMD_ERROR 0x0004 #define SCP_CMD_MNG_LIST_REQ 0x0005 #define SCP_CMD_MNG_LIST 0x0006 #define SCP_CMD_MNG_ACTION 0x0007 #endif xrdp-0.6.0/sesman/libscp/libscp_connection.c000066400000000000000000000027611203155130500210740ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2005-2010 */ /** * * @file libscp_connection.c * @brief SCP_CONNECTION handling code * @author Simone Fedele * */ #include "libscp_connection.h" extern struct log_config* s_log; struct SCP_CONNECTION* scp_connection_create(int sck) { struct SCP_CONNECTION* conn; conn = g_malloc(sizeof(struct SCP_CONNECTION), 0); if (0 == conn) { log_message(s_log, LOG_LEVEL_WARNING, "[connection:%d] connection create: malloc error", __LINE__); return 0; } conn->in_sck=sck; make_stream(conn->in_s); init_stream(conn->in_s, 8196); make_stream(conn->out_s); init_stream(conn->out_s, 8196); return conn; } void scp_connection_destroy(struct SCP_CONNECTION* c) { free_stream(c->in_s); free_stream(c->out_s); g_free(c); } xrdp-0.6.0/sesman/libscp/libscp_connection.h000066400000000000000000000025071203155130500210770ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2005-2010 */ /** * * @file libscp_connection.h * @brief SCP_CONNECTION handling code * @author Simone Fedele * */ #ifndef LIBSCP_CONNECTION_H #define LIBSCP_CONNECTION_H #include "libscp.h" /** * * @brief creates a new connection * @param sck the connection socket * * @return a struct SCP_CONNECTION* object on success, NULL otherwise * */ struct SCP_CONNECTION* scp_connection_create(int sck); /** * * @brief destroys a struct SCP_CONNECTION* object * @param c the object to be destroyed * */ void scp_connection_destroy(struct SCP_CONNECTION* c); #endif xrdp-0.6.0/sesman/libscp/libscp_init.c000066400000000000000000000022261203155130500176740ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2005-2010 */ /** * * @file libscp_init.c * @brief libscp initialization code * @author Simone Fedele * */ #include "libscp_init.h" struct log_config* s_log; /* server API */ int DEFAULT_CC scp_init(struct log_config* log) { if (0 == log) { return 1; } s_log = log; scp_lock_init(); log_message(s_log, LOG_LEVEL_WARNING, "[init:%d] libscp initialized", __LINE__); return 0; } xrdp-0.6.0/sesman/libscp/libscp_init.h000066400000000000000000000024031203155130500176760ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2005-2010 */ /** * * @file libscp_init.h * @brief libscp initialization code header * @author Simone Fedele * */ #ifndef LIBSCP_INIT_H #define LIBSCP_INIT_H #include "log.h" #include "libscp.h" /** * * @brief version neutral server accept function * @param c connection descriptor * @param s session descriptor pointer address. * it will return a newely allocated descriptor. * It this memory needs to be g_free()d * */ int DEFAULT_CC scp_init(struct log_config* log); #endif xrdp-0.6.0/sesman/libscp/libscp_lock.c000066400000000000000000000102131203155130500176540ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2005-2010 session manager linux only */ #include "libscp_lock.h" #include #include pthread_mutex_t lock_fork; /* this lock protects the counters */ pthread_mutexattr_t lock_fork_attr; /* mutex attributes */ sem_t lock_fork_req; /* semaphore on which the process that are going to fork suspend on */ sem_t lock_fork_wait; /* semaphore on which the suspended process wait on */ int lock_fork_forkers_count; /* threads that want to fork */ int lock_fork_blockers_count; /* threads thar are blocking fork */ int lock_fork_waiting_count; /* threads suspended until the fork finishes */ void DEFAULT_CC scp_lock_init(void) { /* initializing fork lock */ pthread_mutexattr_init(&lock_fork_attr); pthread_mutex_init(&lock_fork, &lock_fork_attr); sem_init(&lock_fork_req, 0, 0); sem_init(&lock_fork_wait, 0, 0); /* here we don't use locking because lock_init() should be called BEFORE */ /* any thread is created */ lock_fork_blockers_count=0; lock_fork_waiting_count=0; lock_fork_forkers_count=0; } /******************************************************************************/ void DEFAULT_CC scp_lock_fork_request(void) { /* lock mutex */ pthread_mutex_lock(&lock_fork); if (lock_fork_blockers_count == 0) { /* if noone is blocking fork(), then we're allowed to fork */ sem_post(&lock_fork_req); } lock_fork_forkers_count++; pthread_mutex_unlock(&lock_fork); /* we wait to be allowed to fork() */ sem_wait(&lock_fork_req); } /******************************************************************************/ void DEFAULT_CC scp_lock_fork_release(void) { pthread_mutex_lock(&lock_fork); lock_fork_forkers_count--; /* if there's someone else that want to fork, we let him fork() */ if (lock_fork_forkers_count > 0) { sem_post(&lock_fork_req); } for (;lock_fork_waiting_count > 0; lock_fork_waiting_count--) { /* waking up the other processes */ sem_post(&lock_fork_wait); } pthread_mutex_unlock(&lock_fork); } /******************************************************************************/ void DEFAULT_CC scp_lock_fork_critical_section_end(int blocking) { //LOG_DBG("lock_fork_critical_secection_end()",0); /* lock mutex */ pthread_mutex_lock(&lock_fork); if (blocking == LIBSCP_LOCK_FORK_BLOCKER) { lock_fork_blockers_count--; } /* if there's someone who wants to fork and we're the last blocking */ /* then we let him go */ if ((lock_fork_blockers_count == 0) && (lock_fork_forkers_count>0)) { sem_post(&lock_fork_req); } pthread_mutex_unlock(&lock_fork); } /******************************************************************************/ int DEFAULT_CC scp_lock_fork_critical_section_start(void) { //LOG_DBG("lock_fork_critical_secection_start()",0); do { pthread_mutex_lock(&lock_fork); /* someone requested to fork */ if (lock_fork_forkers_count > 0) { lock_fork_waiting_count++; pthread_mutex_unlock(&lock_fork); /* we wait until the fork finishes */ sem_wait(&lock_fork_wait); } else { /* no fork, so we can go on... */ lock_fork_blockers_count++; pthread_mutex_unlock(&lock_fork); return LIBSCP_LOCK_FORK_BLOCKER; } } while (1); /* we'll never get here */ return LIBSCP_LOCK_FORK_WAITING; } xrdp-0.6.0/sesman/libscp/libscp_lock.h000066400000000000000000000032371203155130500176710ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2005-2010 */ #ifndef LIBSCP_LOCK_H #define LIBSCP_LOCK_H #include "libscp_types.h" #define LIBSCP_LOCK_FORK_BLOCKER 1 #define LIBSCP_LOCK_FORK_WAITING 0 /** * * @brief initializes all the locks * */ void DEFAULT_CC scp_lock_init(void); /** * * @brief requires to fork a new child process * */ void DEFAULT_CC scp_lock_fork_request(void); /** * * @brief releases a fork() request * */ void DEFAULT_CC scp_lock_fork_release(void); /** * * @brief starts a section that is critical for forking * * starts a section that is critical for forking, that is noone can fork() * while i'm in a critical section. But if someone wanted to fork we have * to wait until he finishes with lock_fork_release() * * @return * */ int DEFAULT_CC scp_lock_fork_critical_section_start(void); /** * * @brief closes the critical section * */ void DEFAULT_CC scp_lock_fork_critical_section_end(int blocking); #endif xrdp-0.6.0/sesman/libscp/libscp_session.c000066400000000000000000000227251203155130500204220ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2005-2010 */ /** * * @file libscp_session.c * @brief SCP_SESSION handling code * @author Simone Fedele * */ #include "libscp_session.h" #include #include #include extern struct log_config* s_log; /*******************************************************************/ struct SCP_SESSION* scp_session_create() { struct SCP_SESSION* s; s = (struct SCP_SESSION*)g_malloc(sizeof(struct SCP_SESSION), 1); if (0 == s) { log_message(s_log, LOG_LEVEL_WARNING, "[session:%d] session create: malloc error", __LINE__); return 0; } return s; } /*******************************************************************/ int scp_session_set_type(struct SCP_SESSION* s, tui8 type) { switch (type) { case SCP_SESSION_TYPE_XVNC: s->type = SCP_SESSION_TYPE_XVNC; break; case SCP_SESSION_TYPE_XRDP: s->type = SCP_SESSION_TYPE_XRDP; break; case SCP_SESSION_TYPE_MANAGE: s->type = SCP_SESSION_TYPE_MANAGE; s->mng = (struct SCP_MNG_DATA*)g_malloc(sizeof(struct SCP_MNG_DATA), 1); if (NULL == s->mng) { log_message(s_log, LOG_LEVEL_ERROR, "[session:%d] set_type: internal error", __LINE__); return 1; } break; default: log_message(s_log, LOG_LEVEL_WARNING, "[session:%d] set_type: unknown type", __LINE__); return 1; } return 0; } /*******************************************************************/ int scp_session_set_version(struct SCP_SESSION* s, tui32 version) { switch (version) { case 0: s->version = 0; break; case 1: s->version = 1; break; default: log_message(s_log, LOG_LEVEL_WARNING, "[session:%d] set_version: unknown version", __LINE__); return 1; } return 0; } /*******************************************************************/ int scp_session_set_height(struct SCP_SESSION* s, tui16 h) { s->height = h; return 0; } /*******************************************************************/ int scp_session_set_width(struct SCP_SESSION* s, tui16 w) { s->width = w; return 0; } /*******************************************************************/ int scp_session_set_bpp(struct SCP_SESSION* s, tui8 bpp) { switch (bpp) { case 8: case 15: case 16: case 24: s->bpp = bpp; default: return 1; } return 0; } /*******************************************************************/ int scp_session_set_rsr(struct SCP_SESSION* s, tui8 rsr) { if (s->rsr) { s->rsr = 1; } else { s->rsr = 0; } return 0; } /*******************************************************************/ int scp_session_set_locale(struct SCP_SESSION* s, char* str) { if (0 == str) { log_message(s_log, LOG_LEVEL_WARNING, "[session:%d] set_locale: null locale", __LINE__); s->locale[0]='\0'; return 1; } g_strncpy(s->locale, str, 17); s->locale[17]='\0'; return 0; } /*******************************************************************/ int scp_session_set_username(struct SCP_SESSION* s, char* str) { if (0 == str) { log_message(s_log, LOG_LEVEL_WARNING, "[session:%d] set_username: null username", __LINE__); return 1; } if (0 != s->username) { g_free(s->username); } s->username = g_strdup(str); if (0 == s->username) { log_message(s_log, LOG_LEVEL_WARNING, "[session:%d] set_username: strdup error", __LINE__); return 1; } return 0; } /*******************************************************************/ int scp_session_set_password(struct SCP_SESSION* s, char* str) { if (0 == str) { log_message(s_log, LOG_LEVEL_WARNING, "[session:%d] set_password: null password", __LINE__); return 1; } if (0 != s->password) { g_free(s->password); } s->password = g_strdup(str); if (0 == s->password) { log_message(s_log, LOG_LEVEL_WARNING, "[session:%d] set_password: strdup error", __LINE__); return 1; } return 0; } /*******************************************************************/ int scp_session_set_domain(struct SCP_SESSION* s, char* str) { if (0 == str) { log_message(s_log, LOG_LEVEL_WARNING, "[session:%d] set_domain: null domain", __LINE__); return 1; } if (0 != s->domain) { g_free(s->domain); } s->domain = g_strdup(str); if (0 == s->domain) { log_message(s_log, LOG_LEVEL_WARNING, "[session:%d] set_domain: strdup error", __LINE__); return 1; } return 0; } /*******************************************************************/ int scp_session_set_program(struct SCP_SESSION* s, char* str) { if (0 == str) { log_message(s_log, LOG_LEVEL_WARNING, "[session:%d] set_program: null program", __LINE__); return 1; } if (0 != s->program) { g_free(s->program); } s->program = g_strdup(str); if (0 == s->program) { log_message(s_log, LOG_LEVEL_WARNING, "[session:%d] set_program: strdup error", __LINE__); return 1; } return 0; } /*******************************************************************/ int scp_session_set_directory(struct SCP_SESSION* s, char* str) { if (0 == str) { log_message(s_log, LOG_LEVEL_WARNING, "[session:%d] set_directory: null directory", __LINE__); return 1; } if (0 != s->directory) { g_free(s->directory); } s->directory = g_strdup(str); if (0 == s->directory) { log_message(s_log, LOG_LEVEL_WARNING, "[session:%d] set_directory: strdup error", __LINE__); return 1; } return 0; } /*******************************************************************/ int scp_session_set_client_ip(struct SCP_SESSION* s, char* str) { if (0 == str) { log_message(s_log, LOG_LEVEL_WARNING, "[session:%d] set_client_ip: null ip", __LINE__); return 1; } if (0 != s->client_ip) { g_free(s->client_ip); } s->client_ip = g_strdup(str); if (0 == s->client_ip) { log_message(s_log, LOG_LEVEL_WARNING, "[session:%d] set_client_ip: strdup error", __LINE__); return 1; } return 0; } /*******************************************************************/ int scp_session_set_hostname(struct SCP_SESSION* s, char* str) { if (0 == str) { log_message(s_log, LOG_LEVEL_WARNING, "[session:%d] set_hostname: null hostname", __LINE__); return 1; } if (0 != s->hostname) { g_free(s->hostname); } s->hostname = g_strdup(str); if (0 == s->hostname) { log_message(s_log, LOG_LEVEL_WARNING, "[session:%d] set_hostname: strdup error", __LINE__); return 1; } return 0; } /*******************************************************************/ int scp_session_set_errstr(struct SCP_SESSION* s, char* str) { if (0 == str) { log_message(s_log, LOG_LEVEL_WARNING, "[session:%d] set_errstr: null string", __LINE__); return 1; } if (0 != s->errstr) { g_free(s->errstr); } s->errstr = g_strdup(str); if (0 == s->errstr) { log_message(s_log, LOG_LEVEL_WARNING, "[session:%d] set_errstr: strdup error", __LINE__); return 1; } return 0; } /*******************************************************************/ int scp_session_set_display(struct SCP_SESSION* s, SCP_DISPLAY display) { s->display = display; return 0; } /*******************************************************************/ int scp_session_set_addr(struct SCP_SESSION* s, int type, void* addr) { struct in_addr ip4; #ifdef IN6ADDR_ANY_INIT struct in6_addr ip6; #endif int ret; switch (type) { case SCP_ADDRESS_TYPE_IPV4: /* convert from char to 32bit*/ ret = inet_pton(AF_INET, addr, &ip4); if (ret == 0) { log_message(s_log, LOG_LEVEL_WARNING, "[session:%d] set_addr: invalid address", __LINE__); inet_pton(AF_INET, "127.0.0.1", &ip4); g_memcpy(&(s->ipv4addr), &(ip4.s_addr), 4); return 1; } g_memcpy(&(s->ipv4addr), &(ip4.s_addr), 4); break; case SCP_ADDRESS_TYPE_IPV4_BIN: g_memcpy(&(s->ipv4addr), addr, 4); break; #ifdef IN6ADDR_ANY_INIT case SCP_ADDRESS_TYPE_IPV6: /* convert from char to 128bit*/ ret = inet_pton(AF_INET6, addr, &ip6); if (ret == 0) { log_message(s_log, LOG_LEVEL_WARNING, "[session:%d] set_addr: invalid address", __LINE__); inet_pton(AF_INET, "::1", &ip6); g_memcpy(s->ipv6addr, &(ip6.s6_addr), 16); return 1; } g_memcpy(s->ipv6addr, &(ip6.s6_addr), 16); break; case SCP_ADDRESS_TYPE_IPV6_BIN: g_memcpy(s->ipv6addr, addr, 16); break; #endif default: return 1; } return 0; } /*******************************************************************/ void scp_session_destroy(struct SCP_SESSION* s) { g_free(s->username); g_free(s->password); g_free(s->hostname); g_free(s->domain); g_free(s->program); g_free(s->directory); g_free(s->client_ip); g_free(s->errstr); g_free(s->mng); g_free(s); } xrdp-0.6.0/sesman/libscp/libscp_session.h000066400000000000000000000045301203155130500204210ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2005-2010 */ /** * * @file libscp_session.h * @brief SCP_SESSION handling code * @author Simone Fedele * */ #ifndef LIBSCP_SESSION_H #define LIBSCP_SESSION_H #include "libscp.h" /** * * @brief creates a new connection * @param sck the connection socket * * @return a struct SCP_SESSION* object on success, NULL otherwise * */ struct SCP_SESSION* scp_session_create(); int scp_session_set_type(struct SCP_SESSION* s, tui8 type); int scp_session_set_version(struct SCP_SESSION* s, tui32 version); int scp_session_set_height(struct SCP_SESSION* s, tui16 h); int scp_session_set_width(struct SCP_SESSION* s, tui16 w); int scp_session_set_bpp(struct SCP_SESSION* s, tui8 bpp); int scp_session_set_rsr(struct SCP_SESSION* s, tui8 rsr); int scp_session_set_locale(struct SCP_SESSION* s, char* str); int scp_session_set_username(struct SCP_SESSION* s, char* str); int scp_session_set_password(struct SCP_SESSION* s, char* str); int scp_session_set_domain(struct SCP_SESSION* s, char* str); int scp_session_set_program(struct SCP_SESSION* s, char* str); int scp_session_set_directory(struct SCP_SESSION* s, char* str); int scp_session_set_client_ip(struct SCP_SESSION* s, char* str); int scp_session_set_hostname(struct SCP_SESSION* s, char* str); int scp_session_set_addr(struct SCP_SESSION* s, int type, void* addr); int scp_session_set_display(struct SCP_SESSION* s, SCP_DISPLAY display); int scp_session_set_errstr(struct SCP_SESSION* s, char* str); /** * * @brief destroys a session object * @param s the object to be destroyed * */ void scp_session_destroy(struct SCP_SESSION* s); #endif xrdp-0.6.0/sesman/libscp/libscp_tcp.c000066400000000000000000000056211203155130500175210ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2005-2010 */ /** * * @file tcp.c * @brief Tcp stream funcions * @author Jay Sorg, Simone Fedele * */ #include "libscp_tcp.h" #include #include #include #include #include extern struct log_config* s_log; /*****************************************************************************/ int DEFAULT_CC scp_tcp_force_recv(int sck, char* data, int len) { int rcvd; int block; LOG_DBG(s_log, "scp_tcp_force_recv()"); block = scp_lock_fork_critical_section_start(); while (len > 0) { rcvd = g_tcp_recv(sck, data, len, 0); if (rcvd == -1) { if (g_tcp_last_error_would_block(sck)) { g_sleep(1); } else { scp_lock_fork_critical_section_end(block); return 1; } } else if (rcvd == 0) { scp_lock_fork_critical_section_end(block); return 1; } else { data += rcvd; len -= rcvd; } } scp_lock_fork_critical_section_end(block); return 0; } /*****************************************************************************/ int DEFAULT_CC scp_tcp_force_send(int sck, char* data, int len) { int sent; int block; LOG_DBG(s_log, "scp_tcp_force_send()"); block = scp_lock_fork_critical_section_start(); while (len > 0) { sent = g_tcp_send(sck, data, len, 0); if (sent == -1) { if (g_tcp_last_error_would_block(sck)) { g_sleep(1); } else { scp_lock_fork_critical_section_end(block); return 1; } } else if (sent == 0) { scp_lock_fork_critical_section_end(block); return 1; } else { data += sent; len -= sent; } } scp_lock_fork_critical_section_end(block); return 0; } /*****************************************************************************/ int DEFAULT_CC scp_tcp_bind(int sck, char* addr, char* port) { struct sockaddr_in s; memset(&s, 0, sizeof(struct sockaddr_in)); s.sin_family = AF_INET; s.sin_port = htons(atoi(port)); s.sin_addr.s_addr = inet_addr(addr); return bind(sck, (struct sockaddr*)&s, sizeof(struct sockaddr_in)); } xrdp-0.6.0/sesman/libscp/libscp_tcp.h000066400000000000000000000032751203155130500175310ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2005-2010 */ /** * * @file libscp_tcp.h * @brief Tcp stream functions declarations * @author Jay Sorg, Simone Fedele * */ #ifndef LIBSCP_TCP_H #define LIBSCP_TCP_H #include "libscp.h" /** * * @brief Force receiving data from tcp stream * @param sck The socket to read from * @param data Data buffer * @param len Data buffer size * @return 0 on success, 1 on error * */ int DEFAULT_CC scp_tcp_force_recv(int sck, char* data, int len); /** * * @brief Force sending data to tcp stream * @param sck the socket to write to * @param data Data buffer * @param len Data buffer size * @return 0 on success, 1 on error * */ int DEFAULT_CC scp_tcp_force_send(int sck, char* data, int len); /** * * @brief Binds the listening socket * @param sck Listening socket * @param addr Listening address * @param port Listening port * @return 0 on success, -1 on error * */ int DEFAULT_CC scp_tcp_bind(int sck, char* addr, char* port); #endif xrdp-0.6.0/sesman/libscp/libscp_types.h000066400000000000000000000064761203155130500201150ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2005-2010 */ /** * * @file libscp_types.h * @brief libscp data types definitions * @author Simone Fedele * */ #ifndef LIBSCP_TYPES_H #define LIBSCP_TYPES_H #include "os_calls.h" #include "parse.h" #include "arch.h" #include "log.h" #define SCP_SID tui32 #define SCP_DISPLAY tui16 #define SCP_RESOURCE_SHARING_REQUEST_YES 0x01 #define SCP_RESOURCE_SHARING_REQUEST_NO 0x00 #define SCP_SESSION_TYPE_XVNC 0x00 #define SCP_SESSION_TYPE_XRDP 0x01 #define SCP_SESSION_TYPE_MANAGE 0x02 #define SCP_ADDRESS_TYPE_IPV4 0x00 #define SCP_ADDRESS_TYPE_IPV6 0x01 /* used in scp_session_set_addr() */ #define SCP_ADDRESS_TYPE_IPV4_BIN 0x80 #define SCP_ADDRESS_TYPE_IPV6_BIN 0x81 #define SCP_COMMAND_SET_DEFAULT 0x0000 #define SCP_COMMAND_SET_MANAGE 0x0001 #define SCP_COMMAND_SET_RSR 0x0002 #define SCP_SERVER_MAX_LIST_SIZE 100 #include "libscp_types_mng.h" struct SCP_CONNECTION { int in_sck; struct stream* in_s; struct stream* out_s; }; struct SCP_SESSION { tui8 type; tui32 version; tui16 height; tui16 width; tui8 bpp; tui8 rsr; char locale[18]; char* username; char* password; char* hostname; tui8 addr_type; tui32 ipv4addr; tui8 ipv6addr[16]; SCP_DISPLAY display; char* errstr; struct SCP_MNG_DATA* mng; char* domain; char* program; char* directory; char* client_ip; }; struct SCP_DISCONNECTED_SESSION { tui32 SID; tui8 type; tui8 status; tui16 height; tui16 width; tui8 bpp; tui8 idle_days; tui8 idle_hours; tui8 idle_minutes; tui16 conn_year; tui8 conn_month; tui8 conn_day; tui8 conn_hour; tui8 conn_minute; tui8 addr_type; tui32 ipv4addr; tui8 ipv6addr[16]; }; enum SCP_CLIENT_STATES_E { SCP_CLIENT_STATE_OK, SCP_CLIENT_STATE_NETWORK_ERR, SCP_CLIENT_STATE_VERSION_ERR, SCP_CLIENT_STATE_SEQUENCE_ERR, SCP_CLIENT_STATE_SIZE_ERR, SCP_CLIENT_STATE_INTERNAL_ERR, SCP_CLIENT_STATE_SESSION_LIST, SCP_CLIENT_STATE_LIST_OK, SCP_CLIENT_STATE_RESEND_CREDENTIALS, SCP_CLIENT_STATE_CONNECTION_DENIED, SCP_CLIENT_STATE_PWD_CHANGE_REQ, SCP_CLIENT_STATE_RECONNECT_SINGLE, SCP_CLIENT_STATE_SELECTION_CANCEL, SCP_CLIENT_STATE_END }; enum SCP_SERVER_STATES_E { SCP_SERVER_STATE_OK, SCP_SERVER_STATE_VERSION_ERR, SCP_SERVER_STATE_NETWORK_ERR, SCP_SERVER_STATE_SEQUENCE_ERR, SCP_SERVER_STATE_INTERNAL_ERR, SCP_SERVER_STATE_SESSION_TYPE_ERR, SCP_SERVER_STATE_SIZE_ERR, SCP_SERVER_STATE_SELECTION_CANCEL, /*SCP_SERVER_STATE_FORCE_NEW,*/ SCP_SERVER_STATE_START_MANAGE, SCP_SERVER_STATE_MNG_LISTREQ, SCP_SERVER_STATE_MNG_ACTION, SCP_SERVER_STATE_END }; #endif xrdp-0.6.0/sesman/libscp/libscp_types_mng.h000066400000000000000000000022201203155130500207350ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2005-2010 */ /** * * @file libscp_types_mng.h * @brief libscp data types definitions * @author Simone Fedele * */ #ifndef LIBSCP_TYPES_MNG_H #define LIBSCP_TYPES_MNG_H #include "os_calls.h" #include "parse.h" #include "arch.h" #include "log.h" enum SCP_MNG_COMMAND { SCP_MNG_CMD_KILL, SCP_MNG_CMD_DISCONNECT }; struct SCP_MNG_DATA { enum SCP_MNG_COMMAND cmd; SCP_SID sid; }; #endif xrdp-0.6.0/sesman/libscp/libscp_v0.c000066400000000000000000000222741203155130500172630ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2005-2010 */ /** * * @file libscp_v0.c * @brief libscp version 0 code * @author Simone Fedele * */ #include "libscp_v0.h" #include "os_calls.h" extern struct log_config* s_log; /* client API */ /******************************************************************************/ enum SCP_CLIENT_STATES_E scp_v0c_connect(struct SCP_CONNECTION* c, struct SCP_SESSION* s) { tui32 version; tui32 size; tui16 sz; init_stream(c->in_s, c->in_s->size); init_stream(c->out_s, c->in_s->size); LOG_DBG(s_log, "[v0:%d] starting connection", __LINE__); g_tcp_set_non_blocking(c->in_sck); g_tcp_set_no_delay(c->in_sck); s_push_layer(c->out_s, channel_hdr, 8); /* code */ if (s->type == SCP_SESSION_TYPE_XVNC) { out_uint16_be(c->out_s, 0); } else if (s->type == SCP_SESSION_TYPE_XRDP) { out_uint16_be(c->out_s, 10); } else { log_message(s_log, LOG_LEVEL_WARNING, "[v0:%d] connection aborted: network error", __LINE__); return SCP_CLIENT_STATE_INTERNAL_ERR; } sz = g_strlen(s->username); out_uint16_be(c->out_s, sz); out_uint8a(c->out_s, s->username, sz); sz = g_strlen(s->password); out_uint16_be(c->out_s,sz); out_uint8a(c->out_s, s->password, sz); out_uint16_be(c->out_s, s->width); out_uint16_be(c->out_s, s->height); out_uint16_be(c->out_s, s->bpp); s_mark_end(c->out_s); s_pop_layer(c->out_s, channel_hdr); /* version */ out_uint32_be(c->out_s, 0); /* size */ out_uint32_be(c->out_s, c->out_s->end - c->out_s->data); if (0!=scp_tcp_force_send(c->in_sck, c->out_s->data, c->out_s->end - c->out_s->data)) { log_message(s_log, LOG_LEVEL_WARNING, "[v0:%d] connection aborted: network error", __LINE__); return SCP_CLIENT_STATE_NETWORK_ERR; } if (0!=scp_tcp_force_recv(c->in_sck, c->in_s->data, 8)) { log_message(s_log, LOG_LEVEL_WARNING, "[v0:%d] connection aborted: network error", __LINE__); return SCP_CLIENT_STATE_NETWORK_ERR; } in_uint32_be(c->in_s, version); if (0 != version) { log_message(s_log, LOG_LEVEL_WARNING, "[v0:%d] connection aborted: version error", __LINE__); return SCP_CLIENT_STATE_VERSION_ERR; } in_uint32_be(c->in_s, size); if (size < 14) { log_message(s_log, LOG_LEVEL_WARNING, "[v0:%d] connection aborted: packet size error", __LINE__); return SCP_CLIENT_STATE_SIZE_ERR; } /* getting payload */ init_stream(c->in_s, c->in_s->size); if (0!=scp_tcp_force_recv(c->in_sck, c->in_s->data, size - 8)) { log_message(s_log, LOG_LEVEL_WARNING, "[v0:%d] connection aborted: network error", __LINE__); return SCP_CLIENT_STATE_NETWORK_ERR; } /* check code */ in_uint16_be(c->in_s, sz); if (3 != sz) { log_message(s_log, LOG_LEVEL_WARNING, "[v0:%d] connection aborted: sequence error", __LINE__); return SCP_CLIENT_STATE_SEQUENCE_ERR; } /* message payload */ in_uint16_be(c->in_s, sz); if (1 != sz) { log_message(s_log, LOG_LEVEL_WARNING, "[v0:%d] connection aborted: connection denied", __LINE__); return SCP_CLIENT_STATE_CONNECTION_DENIED; } in_uint16_be(c->in_s, sz); s->display = sz; LOG_DBG(s_log, "[v0:%d] connection terminated", __LINE__); return SCP_CLIENT_STATE_END; } /* server API */ /******************************************************************************/ enum SCP_SERVER_STATES_E scp_v0s_accept(struct SCP_CONNECTION* c, struct SCP_SESSION** s, int skipVchk) { tui32 version = 0; tui32 size; struct SCP_SESSION* session = 0; tui16 sz; tui32 code = 0; char buf[257]; if (!skipVchk) { LOG_DBG(s_log, "[v0:%d] starting connection", __LINE__); if (0 == scp_tcp_force_recv(c->in_sck, c->in_s->data, 8)) { c->in_s->end = c->in_s->data + 8; in_uint32_be(c->in_s, version); if (version != 0) { log_message(s_log, LOG_LEVEL_WARNING, "[v0:%d] connection aborted: version error", __LINE__); return SCP_SERVER_STATE_VERSION_ERR; } } else { log_message(s_log, LOG_LEVEL_WARNING, "[v0:%d] connection aborted: network error", __LINE__); return SCP_SERVER_STATE_NETWORK_ERR; } } in_uint32_be(c->in_s, size); init_stream(c->in_s, 8196); if (0 != scp_tcp_force_recv(c->in_sck, c->in_s->data, size - 8)) { log_message(s_log, LOG_LEVEL_WARNING, "[v0:%d] connection aborted: network error", __LINE__); return SCP_SERVER_STATE_NETWORK_ERR; } c->in_s->end = c->in_s->data + (size - 8); in_uint16_be(c->in_s, code); if (code == 0 || code == 10) { session = scp_session_create(); if (0 == session) { log_message(s_log, LOG_LEVEL_WARNING, "[v0:%d] connection aborted: network error", __LINE__); return SCP_SERVER_STATE_INTERNAL_ERR; } scp_session_set_version(session, version); if (code == 0) { scp_session_set_type(session, SCP_SESSION_TYPE_XVNC); } else { scp_session_set_type(session, SCP_SESSION_TYPE_XRDP); } /* reading username */ in_uint16_be(c->in_s, sz); buf[sz]='\0'; in_uint8a(c->in_s, buf, sz); if (0 != scp_session_set_username(session, buf)) { scp_session_destroy(session); log_message(s_log, LOG_LEVEL_WARNING, "[v0:%d] connection aborted: error setting username", __LINE__); return SCP_SERVER_STATE_INTERNAL_ERR; } /* reading password */ in_uint16_be(c->in_s, sz); buf[sz]='\0'; in_uint8a(c->in_s, buf, sz); if (0 != scp_session_set_password(session, buf)) { scp_session_destroy(session); log_message(s_log, LOG_LEVEL_WARNING, "[v0:%d] connection aborted: error setting password", __LINE__); return SCP_SERVER_STATE_INTERNAL_ERR; } /* width */ in_uint16_be(c->in_s, sz); scp_session_set_width(session, sz); /* height */ in_uint16_be(c->in_s, sz); scp_session_set_height(session, sz); /* bpp */ in_uint16_be(c->in_s, sz); scp_session_set_bpp(session, (tui8)sz); if (s_check_rem(c->in_s, 2)) { /* reading domain */ in_uint16_be(c->in_s, sz); if (sz > 0) { in_uint8a(c->in_s, buf, sz); buf[sz] = '\0'; scp_session_set_domain(session, buf); } } if (s_check_rem(c->in_s, 2)) { /* reading program */ in_uint16_be(c->in_s, sz); if (sz > 0) { in_uint8a(c->in_s, buf, sz); buf[sz] = '\0'; scp_session_set_program(session, buf); } } if (s_check_rem(c->in_s, 2)) { /* reading directory */ in_uint16_be(c->in_s, sz); if (sz > 0) { in_uint8a(c->in_s, buf, sz); buf[sz] = '\0'; scp_session_set_directory(session, buf); } } if (s_check_rem(c->in_s, 2)) { /* reading client IP address */ in_uint16_be(c->in_s, sz); if (sz > 0) { in_uint8a(c->in_s, buf, sz); buf[sz] = '\0'; scp_session_set_client_ip(session, buf); } } } else { log_message(s_log, LOG_LEVEL_WARNING, "[v0:%d] connection aborted: sequence error", __LINE__); return SCP_SERVER_STATE_SEQUENCE_ERR; } (*s)=session; return SCP_SERVER_STATE_OK; } /******************************************************************************/ enum SCP_SERVER_STATES_E scp_v0s_allow_connection(struct SCP_CONNECTION* c, SCP_DISPLAY d) { out_uint32_be(c->out_s, 0); /* version */ out_uint32_be(c->out_s, 14); /* size */ out_uint16_be(c->out_s, 3); /* cmd */ out_uint16_be(c->out_s, 1); /* data */ out_uint16_be(c->out_s, d); /* data */ s_mark_end(c->out_s); if (0 != scp_tcp_force_send(c->in_sck, c->out_s->data, c->out_s->end - c->out_s->data)) { log_message(s_log, LOG_LEVEL_WARNING, "[v0:%d] connection aborted: network error", __LINE__); return SCP_SERVER_STATE_NETWORK_ERR; } LOG_DBG(s_log, "[v0:%d] connection terminated (allowed)", __LINE__); return SCP_SERVER_STATE_OK; } /******************************************************************************/ enum SCP_SERVER_STATES_E scp_v0s_deny_connection(struct SCP_CONNECTION* c) { out_uint32_be(c->out_s, 0); /* version */ out_uint32_be(c->out_s, 14); /* size */ out_uint16_be(c->out_s, 3); /* cmd */ out_uint16_be(c->out_s, 0); /* data */ out_uint16_be(c->out_s, 0); /* data */ s_mark_end(c->out_s); if (0 != scp_tcp_force_send(c->in_sck, c->out_s->data, c->out_s->end - c->out_s->data)) { log_message(s_log, LOG_LEVEL_WARNING, "[v0:%d] connection aborted: network error", __LINE__); return SCP_SERVER_STATE_NETWORK_ERR; } LOG_DBG(s_log, "[v0:%d] connection terminated (denied)", __LINE__); return SCP_SERVER_STATE_OK; } xrdp-0.6.0/sesman/libscp/libscp_v0.h000066400000000000000000000036261203155130500172700ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2005-2010 */ /** * * @file libscp_v0.h * @brief libscp version 0 declarations * @author Simone Fedele * */ #ifndef LIBSCP_V0_H #define LIBSCP_V0_H #include "libscp.h" /* client API */ /** * * @brief connects to sesman using scp v0 * @param c connection descriptor * @param s session descriptor * @param d display * */ enum SCP_CLIENT_STATES_E scp_v0c_connect(struct SCP_CONNECTION* c, struct SCP_SESSION* s); /* server API */ /** * * @brief processes the stream using scp version 0 * @param c connection descriptor * @param s session descriptor * @param skipVchk if set to !0 skips the version control (to be used after * scp_vXs_accept() ) * */ enum SCP_SERVER_STATES_E scp_v0s_accept(struct SCP_CONNECTION* c, struct SCP_SESSION** s, int skipVchk); /** * * @brief allows the connection to TS, returning the display port * @param c connection descriptor * */ enum SCP_SERVER_STATES_E scp_v0s_allow_connection(struct SCP_CONNECTION* c, SCP_DISPLAY d); /** * * @brief denies the connection to TS * @param c connection descriptor * */ enum SCP_SERVER_STATES_E scp_v0s_deny_connection(struct SCP_CONNECTION* c); #endif xrdp-0.6.0/sesman/libscp/libscp_v1c.c000066400000000000000000000272041203155130500174250ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2005-2010 */ /** * * @file libscp_v1c.c * @brief libscp version 1 client api code * @author Simone Fedele * */ #include "libscp_v1c.h" #include #include static enum SCP_CLIENT_STATES_E _scp_v1c_check_response(struct SCP_CONNECTION* c, struct SCP_SESSION* s); /* client API */ /* 001 */ enum SCP_CLIENT_STATES_E scp_v1c_connect(struct SCP_CONNECTION* c, struct SCP_SESSION* s) { tui8 sz; tui32 size; init_stream(c->out_s, c->out_s->size); init_stream(c->in_s, c->in_s->size); size = 19 + 17 + 4 + g_strlen(s->hostname) + g_strlen(s->username) + g_strlen(s->password); if (s->addr_type == SCP_ADDRESS_TYPE_IPV4) { size = size + 4; } else { size = size + 16; } /* sending request */ /* header */ out_uint32_be(c->out_s, 1); /* version */ out_uint32_be(c->out_s, size); out_uint16_be(c->out_s, SCP_COMMAND_SET_DEFAULT); out_uint16_be(c->out_s, 1); /* body */ out_uint8(c->out_s, s->type); out_uint16_be(c->out_s, s->height); out_uint16_be(c->out_s, s->width); out_uint8(c->out_s, s->bpp); out_uint8(c->out_s, s->rsr); out_uint8p(c->out_s, s->locale, 17); out_uint8(c->out_s, s->addr_type); if (s->addr_type == SCP_ADDRESS_TYPE_IPV4) { out_uint32_be(c->out_s, s->ipv4addr); } else if (s->addr_type == SCP_ADDRESS_TYPE_IPV6) { out_uint8p(c->out_s, s->ipv6addr, 16); } sz = g_strlen(s->hostname); out_uint8(c->out_s, sz); out_uint8p(c->out_s, s->hostname, sz); sz = g_strlen(s->username); out_uint8(c->out_s, sz); out_uint8p(c->out_s, s->username, sz); sz = g_strlen(s->password); out_uint8(c->out_s, sz); out_uint8p(c->out_s, s->password, sz); if (0 != scp_tcp_force_send(c->in_sck, c->out_s->data, size)) { return SCP_CLIENT_STATE_NETWORK_ERR; } /* wait for response */ return _scp_v1c_check_response(c, s); } /* 004 */ enum SCP_CLIENT_STATES_E scp_v1c_resend_credentials(struct SCP_CONNECTION* c, struct SCP_SESSION* s) { tui8 sz; tui32 size; init_stream(c->out_s, c->out_s->size); init_stream(c->in_s, c->in_s->size); size = 12 + 2 + g_strlen(s->username) + g_strlen(s->password); /* sending request */ /* header */ out_uint32_be(c->out_s, 1); /* version */ out_uint32_be(c->out_s, size); out_uint16_be(c->out_s, SCP_COMMAND_SET_DEFAULT); out_uint16_be(c->out_s, 4); /* body */ sz = g_strlen(s->username); out_uint8(c->out_s, sz); out_uint8p(c->out_s, s->username, sz); sz = g_strlen(s->password); out_uint8(c->out_s, sz); out_uint8p(c->out_s, s->password, sz); if (0 != scp_tcp_force_send(c->in_sck, c->out_s->data, size)) { return SCP_CLIENT_STATE_NETWORK_ERR; } /* wait for response */ return _scp_v1c_check_response(c, s); } /* 021 */ enum SCP_CLIENT_STATES_E scp_v1c_pwd_change(struct SCP_CONNECTION* c, char* newpass); /* 022 */ enum SCP_CLIENT_STATES_E scp_v1c_pwd_change_cancel(struct SCP_CONNECTION* c); /* 041 */ enum SCP_CLIENT_STATES_E scp_v1c_get_session_list(struct SCP_CONNECTION* c, int* scount, struct SCP_DISCONNECTED_SESSION** s) { tui32 version = 1; tui32 size = 12; tui16 cmd = 41; tui32 sescnt = 0; /* total session number */ tui32 sestmp = 0; /* additional total session number */ tui8 pktcnt = 0; /* packet session count */ tui32 totalcnt = 0; /* session counter */ tui8 continued = 0; /* continue flag */ int firstpkt = 1; /* "first packet" flag */ int idx; struct SCP_DISCONNECTED_SESSION* ds = 0; init_stream(c->out_s, c->out_s->size); /* we request session list */ out_uint32_be(c->out_s, version); /* version */ out_uint32_be(c->out_s, size); /* size */ out_uint16_be(c->out_s, SCP_COMMAND_SET_DEFAULT); /* cmdset */ out_uint16_be(c->out_s, cmd); /* cmd */ if (0 != scp_tcp_force_send(c->in_sck, c->out_s->data, size)) { return SCP_CLIENT_STATE_NETWORK_ERR; } do { /* then we wait for server response */ init_stream(c->in_s, c->in_s->size); if (0 != scp_tcp_force_recv(c->in_sck, c->in_s->data, 8)) { return SCP_CLIENT_STATE_NETWORK_ERR; } in_uint32_be(c->in_s, version); if (version != 1) { return SCP_CLIENT_STATE_VERSION_ERR; } in_uint32_be(c->in_s, size); if (size < 12) { return SCP_CLIENT_STATE_SIZE_ERR; } init_stream(c->in_s, c->in_s->size); if (0 != scp_tcp_force_recv(c->in_sck, c->in_s->data, size - 8)) { return SCP_CLIENT_STATE_NETWORK_ERR; } in_uint16_be(c->in_s, cmd); if (cmd != SCP_COMMAND_SET_DEFAULT) { return SCP_CLIENT_STATE_SEQUENCE_ERR; } in_uint16_be(c->in_s, cmd); if (cmd != 42) { return SCP_CLIENT_STATE_SEQUENCE_ERR; } if (firstpkt) { firstpkt = 0; in_uint32_be(c->in_s, sescnt); sestmp = sescnt; ds = g_malloc(sizeof(struct SCP_DISCONNECTED_SESSION) * sescnt, 0); if (ds == 0) { return SCP_CLIENT_STATE_INTERNAL_ERR; } } else { in_uint32_be(c->in_s, sestmp); } in_uint8(c->in_s, continued); in_uint8(c->in_s, pktcnt); for (idx = 0; idx < pktcnt; idx++) { in_uint32_be(c->in_s, (ds[totalcnt]).SID); /* session id */ in_uint8(c->in_s, (ds[totalcnt]).type); in_uint16_be(c->in_s, (ds[totalcnt]).height); in_uint16_be(c->in_s, (ds[totalcnt]).width); in_uint8(c->in_s, (ds[totalcnt]).bpp); in_uint8(c->in_s, (ds[totalcnt]).idle_days); in_uint8(c->in_s, (ds[totalcnt]).idle_hours); in_uint8(c->in_s, (ds[totalcnt]).idle_minutes); in_uint16_be(c->in_s, (ds[totalcnt]).conn_year); in_uint8(c->in_s, (ds[totalcnt]).conn_month); in_uint8(c->in_s, (ds[totalcnt]).conn_day); in_uint8(c->in_s, (ds[totalcnt]).conn_hour); in_uint8(c->in_s, (ds[totalcnt]).conn_minute); in_uint8(c->in_s, (ds[totalcnt]).addr_type); if ((ds[totalcnt]).addr_type == SCP_ADDRESS_TYPE_IPV4) { in_uint32_be(c->in_s, (ds[totalcnt]).ipv4addr); } else if ((ds[totalcnt]).addr_type == SCP_ADDRESS_TYPE_IPV6) { in_uint8a(c->in_s, (ds[totalcnt]).ipv6addr, 16); } totalcnt++; } } while (continued); printf("fine\n"); /* return data... */ (*scount) = sescnt; (*s) = ds; return SCP_CLIENT_STATE_LIST_OK; } /* 043 */ enum SCP_CLIENT_STATES_E scp_v1c_select_session(struct SCP_CONNECTION* c, struct SCP_SESSION* s, SCP_SID sid) { tui32 version = 1; tui32 size = 16; tui16 cmd = 43; init_stream(c->out_s, c->out_s->size); /* sending our selection */ out_uint32_be(c->out_s, version); /* version */ out_uint32_be(c->out_s, size); /* size */ out_uint16_be(c->out_s, SCP_COMMAND_SET_DEFAULT); /* cmdset */ out_uint16_be(c->out_s, cmd); /* cmd */ out_uint32_be(c->out_s, sid); if (0 != scp_tcp_force_send(c->in_sck, c->out_s->data, size)) { return SCP_CLIENT_STATE_NETWORK_ERR; } /* waiting for response.... */ init_stream(c->in_s, c->in_s->size); if (0 != scp_tcp_force_recv(c->in_sck, c->in_s->data, 8)) { return SCP_CLIENT_STATE_NETWORK_ERR; } in_uint32_be(c->in_s, version); if (version != 1) { return SCP_CLIENT_STATE_VERSION_ERR; } in_uint32_be(c->in_s, size); if (size < 12) { return SCP_CLIENT_STATE_SIZE_ERR; } init_stream(c->in_s, c->in_s->size); /* read the rest of the packet */ if (0 != scp_tcp_force_recv(c->in_sck, c->in_s->data, size - 8)) { return SCP_CLIENT_STATE_NETWORK_ERR; } in_uint16_be(c->in_s, cmd); if (cmd != SCP_COMMAND_SET_DEFAULT) { return SCP_CLIENT_STATE_SEQUENCE_ERR; } in_uint16_be(c->in_s, cmd); if (cmd != 46) { return SCP_CLIENT_STATE_SEQUENCE_ERR; } /* session display */ in_uint16_be(c->in_s, (s->display)); /*we don't need to return any data other than the display */ /*because we already sent that */ return SCP_CLIENT_STATE_OK; } /* 044 */ enum SCP_CLIENT_STATES_E scp_v1c_select_session_cancel(struct SCP_CONNECTION* c) { tui32 version = 1; tui32 size = 12; tui16 cmd = 44; init_stream(c->out_s, c->out_s->size); /* sending our selection */ out_uint32_be(c->out_s, version); /* version */ out_uint32_be(c->out_s, size); /* size */ out_uint16_be(c->out_s, SCP_COMMAND_SET_DEFAULT); /* cmdset */ out_uint16_be(c->out_s, cmd); /* cmd */ if (0 != scp_tcp_force_send(c->in_sck, c->out_s->data, size)) { return SCP_CLIENT_STATE_NETWORK_ERR; } return SCP_CLIENT_STATE_END; } static enum SCP_CLIENT_STATES_E _scp_v1c_check_response(struct SCP_CONNECTION* c, struct SCP_SESSION* s) { tui32 version; tui32 size; tui16 cmd; tui16 dim; init_stream(c->in_s, c->in_s->size); if (0 != scp_tcp_force_recv(c->in_sck, c->in_s->data, 8)) { return SCP_CLIENT_STATE_NETWORK_ERR; } in_uint32_be(c->in_s, version); if (version != 1) { return SCP_CLIENT_STATE_VERSION_ERR; } in_uint32_be(c->in_s, size); init_stream(c->in_s, c->in_s->size); /* read the rest of the packet */ if (0 != scp_tcp_force_recv(c->in_sck, c->in_s->data, size - 8)) { return SCP_CLIENT_STATE_NETWORK_ERR; } in_uint16_be(c->in_s, cmd); if (cmd != SCP_COMMAND_SET_DEFAULT) { return SCP_CLIENT_STATE_SEQUENCE_ERR; } in_uint16_be(c->in_s, cmd); if (cmd == 2) /* connection denied */ { in_uint16_be(c->in_s, dim); if (s->errstr != 0) { g_free(s->errstr); } s->errstr = g_malloc(dim + 1, 0); if (s->errstr == 0) { return SCP_CLIENT_STATE_INTERNAL_ERR; } in_uint8a(c->in_s, s->errstr, dim); (s->errstr)[dim] = '\0'; return SCP_CLIENT_STATE_CONNECTION_DENIED; } else if (cmd == 3) /* resend usr/pwd */ { in_uint16_be(c->in_s, dim); if (s->errstr != 0) { g_free(s->errstr); } s->errstr = g_malloc(dim + 1, 0); if (s->errstr == 0) { return SCP_CLIENT_STATE_INTERNAL_ERR; } in_uint8a(c->in_s, s->errstr, dim); (s->errstr)[dim] = '\0'; return SCP_CLIENT_STATE_RESEND_CREDENTIALS; } else if (cmd == 20) /* password change */ { in_uint16_be(c->in_s, dim); if (s->errstr != 0) { g_free(s->errstr); } s->errstr = g_malloc(dim + 1, 0); if (s->errstr == 0) { return SCP_CLIENT_STATE_INTERNAL_ERR; } in_uint8a(c->in_s, s->errstr, dim); (s->errstr)[dim] = '\0'; return SCP_CLIENT_STATE_PWD_CHANGE_REQ; } else if (cmd == 30) /* display */ { in_uint16_be(c->in_s, s->display); return SCP_CLIENT_STATE_OK; } //else if (cmd == 31) /* there's a disconnected session */ //{ // return SCP_CLIENT_STATE_RECONNECT_SINGLE; //} //else if (cmd == 33) /* display of a disconnected session */ //{ // return SCP_CLIENT_STATE_RECONNECT; //} else if (cmd == 40) /* session list */ { return SCP_CLIENT_STATE_SESSION_LIST; } return SCP_CLIENT_STATE_SEQUENCE_ERR; } xrdp-0.6.0/sesman/libscp/libscp_v1c.h000066400000000000000000000033671203155130500174360ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2005-2010 */ /** * * @file libscp_v1c.h * @brief libscp version 1 client api declarations * @author Simone Fedele * */ #ifndef LIBSCP_V1C_H #define LIBSCP_V1C_H #include "libscp.h" /* client API */ /* 001 */ enum SCP_CLIENT_STATES_E scp_v1c_connect(struct SCP_CONNECTION* c, struct SCP_SESSION* s); /* 004 */ enum SCP_CLIENT_STATES_E scp_v1c_resend_credentials(struct SCP_CONNECTION* c, struct SCP_SESSION* s); /* 021 */ enum SCP_CLIENT_STATES_E scp_v1c_pwd_change(struct SCP_CONNECTION* c, char* newpass); /* 022 */ enum SCP_CLIENT_STATES_E scp_v1c_pwd_change_cancel(struct SCP_CONNECTION* c); /* 041 */ enum SCP_CLIENT_STATES_E scp_v1c_get_session_list(struct SCP_CONNECTION* c, int* scount, struct SCP_DISCONNECTED_SESSION** s); /* 043 */ enum SCP_CLIENT_STATES_E scp_v1c_select_session(struct SCP_CONNECTION* c, struct SCP_SESSION* s, SCP_SID sid); /* 044 */ enum SCP_CLIENT_STATES_E scp_v1c_select_session_cancel(struct SCP_CONNECTION* c); #endif xrdp-0.6.0/sesman/libscp/libscp_v1c_mng.c000066400000000000000000000263671203155130500202770ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2005-2010 */ /** * * @file libscp_v1c_mng.c * @brief libscp version 1 client api code - session management * @author Simone Fedele * */ #include "libscp_v1c_mng.h" #include #include extern struct log_config* s_log; static enum SCP_CLIENT_STATES_E _scp_v1c_mng_check_response(struct SCP_CONNECTION* c, struct SCP_SESSION* s); /* client API */ /* 001 */ enum SCP_CLIENT_STATES_E scp_v1c_mng_connect(struct SCP_CONNECTION* c, struct SCP_SESSION* s) { tui8 sz; tui32 size; init_stream(c->out_s, c->out_s->size); init_stream(c->in_s, c->in_s->size); size = 12 + 4 + g_strlen(s->hostname) + g_strlen(s->username) + g_strlen(s->password); if (s->addr_type == SCP_ADDRESS_TYPE_IPV4) { size = size + 4; } else { size = size + 16; } /* sending request */ /* header */ out_uint32_be(c->out_s, 1); /* version */ out_uint32_be(c->out_s, size); out_uint16_be(c->out_s, SCP_COMMAND_SET_MANAGE); out_uint16_be(c->out_s, SCP_CMD_MNG_LOGIN); /* data */ sz = g_strlen(s->username); out_uint8(c->out_s, sz); out_uint8p(c->out_s, s->username, sz); sz = g_strlen(s->password); out_uint8(c->out_s, sz); out_uint8p(c->out_s, s->password, sz); /* address */ out_uint8(c->out_s, s->addr_type); if (s->addr_type == SCP_ADDRESS_TYPE_IPV4) { out_uint32_be(c->out_s, s->ipv4addr); } else { out_uint8p(c->out_s, s->ipv6addr, 16); } /* hostname */ sz = g_strlen(s->hostname); out_uint8(c->out_s, sz); out_uint8p(c->out_s, s->hostname, sz); if (0 != scp_tcp_force_send(c->in_sck, c->out_s->data, size)) { log_message(s_log, LOG_LEVEL_WARNING, "[v1c_mng:%d] connection aborted: network error", __LINE__); return SCP_CLIENT_STATE_NETWORK_ERR; } /* wait for response */ return _scp_v1c_mng_check_response(c, s); } /* 004 */ enum SCP_CLIENT_STATES_E scp_v1c_mng_get_session_list(struct SCP_CONNECTION* c, int* scount, struct SCP_DISCONNECTED_SESSION** s) { tui32 version = 1; tui32 size = 12; tui16 cmd = SCP_CMD_MNG_LIST_REQ; /* request session list */ tui32 sescnt = 0; /* total session number */ tui32 sestmp = 0; /* additional total session number */ tui8 pktcnt = 0; /* packet session count */ tui32 totalcnt = 0; /* session counter */ tui8 continued = 0; /* continue flag */ int firstpkt = 1; /* "first packet" flag */ int idx; struct SCP_DISCONNECTED_SESSION* ds = 0; // tui8 addr[16]; init_stream(c->out_s, c->out_s->size); /* we request session list */ out_uint32_be(c->out_s, version); /* version */ out_uint32_be(c->out_s, size); /* size */ out_uint16_be(c->out_s, SCP_COMMAND_SET_MANAGE); /* cmdset */ out_uint16_be(c->out_s, cmd); /* cmd */ if (0 != scp_tcp_force_send(c->in_sck, c->out_s->data, size)) { log_message(s_log, LOG_LEVEL_WARNING, "[v1c_mng:%d] connection aborted: network error", __LINE__); return SCP_CLIENT_STATE_NETWORK_ERR; } do { /* then we wait for server response */ init_stream(c->in_s, c->in_s->size); if (0 != scp_tcp_force_recv(c->in_sck, c->in_s->data, 8)) { log_message(s_log, LOG_LEVEL_WARNING, "[v1c_mng:%d] connection aborted: network error", __LINE__); return SCP_CLIENT_STATE_NETWORK_ERR; } in_uint32_be(c->in_s, version); if (version != 1) { log_message(s_log, LOG_LEVEL_WARNING, "[v1c_mng:%d] connection aborted: version error", __LINE__); return SCP_CLIENT_STATE_VERSION_ERR; } in_uint32_be(c->in_s, size); if (size < 12) { log_message(s_log, LOG_LEVEL_WARNING, "[v1c_mng:%d] connection aborted: size error", __LINE__); return SCP_CLIENT_STATE_SIZE_ERR; } init_stream(c->in_s, c->in_s->size); if (0 != scp_tcp_force_recv(c->in_sck, c->in_s->data, size - 8)) { log_message(s_log, LOG_LEVEL_WARNING, "[v1c_mng:%d] connection aborted: network error", __LINE__); return SCP_CLIENT_STATE_NETWORK_ERR; } in_uint16_be(c->in_s, cmd); if (cmd != SCP_COMMAND_SET_MANAGE) { log_message(s_log, LOG_LEVEL_WARNING, "[v1c_mng:%d] connection aborted: sequence error", __LINE__); return SCP_CLIENT_STATE_SEQUENCE_ERR; } in_uint16_be(c->in_s, cmd); if (cmd != SCP_CMD_MNG_LIST) /* session list */ { log_message(s_log, LOG_LEVEL_WARNING, "[v1c_mng:%d] connection aborted: sequence error", __LINE__); return SCP_CLIENT_STATE_SEQUENCE_ERR; } if (firstpkt) { firstpkt = 0; in_uint32_be(c->in_s, sescnt); sestmp = sescnt; if (0 == sescnt) { /* return data... */ (*scount) = sescnt; (*s) = NULL; LOG_DBG(s_log, "[v1c_mng] end list - no session on TS"); return SCP_CLIENT_STATE_LIST_OK; } ds = g_malloc(sizeof(struct SCP_DISCONNECTED_SESSION) * sescnt, 0); if (ds == 0) { log_message(s_log, LOG_LEVEL_WARNING, "[v1c_mng:%d] connection aborted: internal error", __LINE__); return SCP_CLIENT_STATE_INTERNAL_ERR; } } else { in_uint32_be(c->in_s, sestmp); } in_uint8(c->in_s, continued); in_uint8(c->in_s, pktcnt); for (idx = 0; idx < pktcnt; idx++) { in_uint32_be(c->in_s, (ds[totalcnt]).SID); /* session id */ in_uint8(c->in_s, (ds[totalcnt]).type); in_uint16_be(c->in_s, (ds[totalcnt]).height); in_uint16_be(c->in_s, (ds[totalcnt]).width); in_uint8(c->in_s, (ds[totalcnt]).bpp); in_uint8(c->in_s, (ds[totalcnt]).idle_days); in_uint8(c->in_s, (ds[totalcnt]).idle_hours); in_uint8(c->in_s, (ds[totalcnt]).idle_minutes); in_uint16_be(c->in_s, (ds[totalcnt]).conn_year); in_uint8(c->in_s, (ds[totalcnt]).conn_month); in_uint8(c->in_s, (ds[totalcnt]).conn_day); in_uint8(c->in_s, (ds[totalcnt]).conn_hour); in_uint8(c->in_s, (ds[totalcnt]).conn_minute); in_uint8(c->in_s, (ds[totalcnt]).addr_type); if ((ds[totalcnt]).addr_type == SCP_ADDRESS_TYPE_IPV4) { in_uint32_be(c->in_s, (ds[totalcnt]).ipv4addr); } if ((ds[totalcnt]).addr_type == SCP_ADDRESS_TYPE_IPV6) { in_uint8a(c->in_s, (ds[totalcnt]).ipv6addr, 16); } totalcnt++; } } while (continued); /* return data... */ (*scount) = sescnt; (*s) = ds; LOG_DBG(s_log, "[v1c_mng] end list"); return SCP_CLIENT_STATE_LIST_OK; } /* 043 * / enum SCP_CLIENT_STATES_E scp_v1c_select_session(struct SCP_CONNECTION* c, struct SCP_SESSION* s, SCP_SID sid) { tui32 version = 1; tui32 size = 16; tui16 cmd = 43; init_stream(c->out_s, c->out_s->size); / * sending our selection * / out_uint32_be(c->out_s, version); / * version * / out_uint32_be(c->out_s, size); / * size * / out_uint16_be(c->out_s, SCP_COMMAND_SET_DEFAULT); / * cmdset * / out_uint16_be(c->out_s, cmd); / * cmd * / out_uint32_be(c->out_s, sid); if (0 != scp_tcp_force_send(c->in_sck, c->out_s->data, size)) { return SCP_CLIENT_STATE_NETWORK_ERR; } / * waiting for response.... * / init_stream(c->in_s, c->in_s->size); if (0 != scp_tcp_force_recv(c->in_sck, c->in_s->data, 8)) { return SCP_CLIENT_STATE_NETWORK_ERR; } in_uint32_be(c->in_s, version); if (version != 1) { return SCP_CLIENT_STATE_VERSION_ERR; } in_uint32_be(c->in_s, size); if (size < 12) { return SCP_CLIENT_STATE_SIZE_ERR; } init_stream(c->in_s, c->in_s->size); / * read the rest of the packet * / if (0 != scp_tcp_force_recv(c->in_sck, c->in_s->data, size - 8)) { return SCP_CLIENT_STATE_NETWORK_ERR; } in_uint16_be(c->in_s, cmd); if (cmd != SCP_COMMAND_SET_DEFAULT) { return SCP_CLIENT_STATE_SEQUENCE_ERR; } in_uint16_be(c->in_s, cmd); if (cmd != 46) { return SCP_CLIENT_STATE_SEQUENCE_ERR; } / * session display * / in_uint16_be(c->in_s, (s->display)); / *we don't need to return any data other than the display * / / *because we already sent that * / return SCP_CLIENT_STATE_OK; }*/ /* 044 * / enum SCP_CLIENT_STATES_E scp_v1c_select_session_cancel(struct SCP_CONNECTION* c) { tui32 version = 1; tui32 size = 12; tui16 cmd = 44; init_stream(c->out_s, c->out_s->size); / * sending our selection * / out_uint32_be(c->out_s, version); / * version * / out_uint32_be(c->out_s, size); / * size * / out_uint16_be(c->out_s, SCP_COMMAND_SET_DEFAULT); / * cmdset * / out_uint16_be(c->out_s, cmd); / * cmd * / if (0 != scp_tcp_force_send(c->in_sck, c->out_s->data, size)) { return SCP_CLIENT_STATE_NETWORK_ERR; } return SCP_CLIENT_STATE_END; }*/ static enum SCP_CLIENT_STATES_E _scp_v1c_mng_check_response(struct SCP_CONNECTION* c, struct SCP_SESSION* s) { tui32 version; tui32 size; tui16 cmd; tui8 dim; char buf[257]; init_stream(c->in_s, c->in_s->size); if (0 != scp_tcp_force_recv(c->in_sck, c->in_s->data, 8)) { log_message(s_log, LOG_LEVEL_WARNING, "[v1c_mng:%d] connection aborted: network error", __LINE__); return SCP_CLIENT_STATE_NETWORK_ERR; } in_uint32_be(c->in_s, version); if (version != 1) { log_message(s_log, LOG_LEVEL_WARNING, "[v1c_mng:%d] connection aborted: version error", __LINE__); return SCP_CLIENT_STATE_VERSION_ERR; } in_uint32_be(c->in_s, size); init_stream(c->in_s, c->in_s->size); /* read the rest of the packet */ if (0 != scp_tcp_force_recv(c->in_sck, c->in_s->data, size - 8)) { log_message(s_log, LOG_LEVEL_WARNING, "[v1c_mng:%d] connection aborted: network error", __LINE__); return SCP_CLIENT_STATE_NETWORK_ERR; } in_uint16_be(c->in_s, cmd); if (cmd != SCP_COMMAND_SET_MANAGE) { log_message(s_log, LOG_LEVEL_WARNING, "[v1c_mng:%d] connection aborted: sequence error", __LINE__); return SCP_CLIENT_STATE_SEQUENCE_ERR; } in_uint16_be(c->in_s, cmd); if (cmd == SCP_CMD_MNG_LOGIN_ALLOW) /* connection ok */ { log_message(s_log, LOG_LEVEL_INFO, "[v1c_mng:%d] connection ok", __LINE__); return SCP_CLIENT_STATE_OK; } else if (cmd == SCP_CMD_MNG_LOGIN_DENY) /* connection denied */ { in_uint8(c->in_s, dim); buf[dim]='\0'; in_uint8a(c->in_s, buf, dim); scp_session_set_errstr(s, buf); log_message(s_log, LOG_LEVEL_INFO, "[v1c_mng:%d] connection denied: %s", __LINE__ , s->errstr); return SCP_CLIENT_STATE_CONNECTION_DENIED; } log_message(s_log, LOG_LEVEL_WARNING, "[v1c-mng:%d] connection aborted: sequence error", __LINE__); return SCP_CLIENT_STATE_SEQUENCE_ERR; } xrdp-0.6.0/sesman/libscp/libscp_v1c_mng.h000066400000000000000000000032271203155130500202720ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2005-2010 */ /** * * @file libscp_v1c_mng.h * @brief libscp version 1 client api declarations - session management * @author Simone Fedele * */ #ifndef LIBSCP_V1C_MNG_H #define LIBSCP_V1C_MNG_H #include "libscp.h" /* client API */ /* 001 */ enum SCP_CLIENT_STATES_E scp_v1c_mng_connect(struct SCP_CONNECTION* c, struct SCP_SESSION* s); /* 004 * / enum SCP_CLIENT_STATES_E scp_v1c_resend_credentials(struct SCP_CONNECTION* c, struct SCP_SESSION* s); / * 021 * / enum SCP_CLIENT_STATES_E scp_v1c_pwd_change(struct SCP_CONNECTION* c, char* newpass); / * 022 * / enum SCP_CLIENT_STATES_E scp_v1c_pwd_change_cancel(struct SCP_CONNECTION* c); */ /* 041 */ enum SCP_CLIENT_STATES_E scp_v1c_mng_get_session_list(struct SCP_CONNECTION* c, int* scount, struct SCP_DISCONNECTED_SESSION** s); /* 044 */ enum SCP_CLIENT_STATES_E scp_v1c_select_session_cancel(struct SCP_CONNECTION* c); #endif xrdp-0.6.0/sesman/libscp/libscp_v1s.c000066400000000000000000000452401203155130500174450ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2005-2010 */ /** * * @file libscp_v1s.c * @brief libscp version 1 server api code * @author Simone Fedele * */ #ifndef LIBSCP_V1S_C #define LIBSCP_V1S_C #include "libscp_v1s.h" extern struct log_config* s_log; /* server API */ enum SCP_SERVER_STATES_E scp_v1s_accept(struct SCP_CONNECTION* c, struct SCP_SESSION** s, int skipVchk) { struct SCP_SESSION* session; tui32 version; tui32 size; tui16 cmdset; tui16 cmd; tui8 sz; char buf[257]; if (!skipVchk) { if (0==scp_tcp_force_recv(c->in_sck, c->in_s->data, 8)) { in_uint32_be(c->in_s, version); if (version != 1) { log_message(s_log, LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: version error", __LINE__); return SCP_SERVER_STATE_VERSION_ERR; } } else { log_message(s_log, LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: network error", __LINE__); return SCP_SERVER_STATE_NETWORK_ERR; } } in_uint32_be(c->in_s, size); if (size < 12) { log_message(s_log, LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: size error", __LINE__); return SCP_SERVER_STATE_SIZE_ERR; } init_stream(c->in_s, c->in_s->size); if (0 != scp_tcp_force_recv(c->in_sck, c->in_s->data, (size-8))) { log_message(s_log, LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: network error", __LINE__); return SCP_SERVER_STATE_NETWORK_ERR; } /* reading command set */ in_uint16_be(c->in_s, cmdset); /* if we are starting a management session */ if (cmdset == SCP_COMMAND_SET_MANAGE) { log_message(s_log, LOG_LEVEL_DEBUG, "[v1s:%d] requested management connection", __LINE__); /* should return SCP_SERVER_STATE_START_MANAGE */ return scp_v1s_mng_accept(c, s); } /* if we started with resource sharing... */ if (cmdset == SCP_COMMAND_SET_RSR) { log_message(s_log, LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: sequence error", __LINE__); return SCP_SERVER_STATE_SEQUENCE_ERR; } /* reading command */ in_uint16_be(c->in_s, cmd); if (cmd != 1) { log_message(s_log, LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: sequence error", __LINE__); return SCP_SERVER_STATE_SEQUENCE_ERR; } session = scp_session_create(); if (0 == session) { log_message(s_log, LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: internal error (malloc returned NULL)", __LINE__); return SCP_SERVER_STATE_INTERNAL_ERR; } scp_session_set_version(session, 1); in_uint8(c->in_s, sz); if ((sz != SCP_SESSION_TYPE_XVNC) && (sz != SCP_SESSION_TYPE_XRDP)) { scp_session_destroy(session); log_message(s_log, LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: unknown session type", __LINE__); return SCP_SERVER_STATE_SESSION_TYPE_ERR; } scp_session_set_type(session, sz); in_uint16_be(c->in_s, cmd); scp_session_set_height(session, cmd); in_uint16_be(c->in_s, cmd); scp_session_set_height(session, cmd); in_uint8(c->in_s, sz); scp_session_set_bpp(session, sz); in_uint8(c->in_s, sz); scp_session_set_rsr(session, sz); in_uint8a(c->in_s, buf, 17); buf[17]='\0'; scp_session_set_locale(session, buf); in_uint8(c->in_s, sz); if (sz == SCP_ADDRESS_TYPE_IPV4) { in_uint32_be(c->in_s, size); scp_session_set_addr(session, SCP_ADDRESS_TYPE_IPV4_BIN, &size); } else if (sz == SCP_ADDRESS_TYPE_IPV6) { in_uint8a(c->in_s, buf, 16); scp_session_set_addr(session, SCP_ADDRESS_TYPE_IPV6_BIN, buf); } buf[256] = '\0'; /* reading hostname */ in_uint8(c->in_s, sz); buf[sz]='\0'; in_uint8a(c->in_s, buf, sz); if (0 != scp_session_set_hostname(session, buf)) { scp_session_destroy(session); log_message(s_log, LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: internal error", __LINE__); return SCP_SERVER_STATE_INTERNAL_ERR; } /* reading username */ in_uint8(c->in_s, sz); buf[sz]='\0'; in_uint8a(c->in_s, buf, sz); if (0 != scp_session_set_username(session, buf)) { scp_session_destroy(session); log_message(s_log, LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: internal error", __LINE__); return SCP_SERVER_STATE_INTERNAL_ERR; } /* reading password */ in_uint8(c->in_s, sz); buf[sz]='\0'; in_uint8a(c->in_s, buf, sz); if (0 != scp_session_set_password(session, buf)) { scp_session_destroy(session); log_message(s_log, LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: internal error", __LINE__); return SCP_SERVER_STATE_INTERNAL_ERR; } /* returning the struct */ (*s)=session; return SCP_SERVER_STATE_OK; } enum SCP_SERVER_STATES_E scp_v1s_deny_connection(struct SCP_CONNECTION* c, char* reason) { int rlen; init_stream(c->out_s,c->out_s->size); /* forcing message not to exceed 64k */ rlen = g_strlen(reason); if (rlen > 65535) { rlen = 65535; } out_uint32_be(c->out_s, 1); /* packet size: 4 + 4 + 2 + 2 + 2 + strlen(reason)*/ /* version + size + cmdset + cmd + msglen + msg */ out_uint32_be(c->out_s, rlen+14); out_uint16_be(c->out_s, SCP_COMMAND_SET_DEFAULT); out_uint16_be(c->out_s, 2); out_uint16_be(c->out_s, rlen); out_uint8p(c->out_s, reason, rlen); if (0!=scp_tcp_force_send(c->in_sck, c->out_s->data, rlen+14)) { log_message(s_log, LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: network error", __LINE__); return SCP_SERVER_STATE_NETWORK_ERR; } return SCP_SERVER_STATE_END; } enum SCP_SERVER_STATES_E scp_v1s_request_password(struct SCP_CONNECTION* c, struct SCP_SESSION* s, char* reason) { tui8 sz; tui32 version; tui32 size; tui16 cmdset; tui16 cmd; int rlen; char buf[257]; init_stream(c->in_s, c->in_s->size); init_stream(c->out_s, c->out_s->size); /* forcing message not to exceed 64k */ rlen = g_strlen(reason); if (rlen > 65535) { rlen = 65535; } /* send password request */ version=1; cmd=3; out_uint32_be(c->out_s, version); /* version */ out_uint32_be(c->out_s, 14+rlen); /* size */ out_uint16_be(c->out_s, SCP_COMMAND_SET_DEFAULT); /* cmdset */ out_uint16_be(c->out_s, cmd); /* cmd */ out_uint16_be(c->out_s, rlen); out_uint8p(c->out_s, reason, rlen); if (0!=scp_tcp_force_send(c->in_sck, c->out_s->data, 14+rlen)) { log_message(s_log, LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: network error", __LINE__); return SCP_SERVER_STATE_NETWORK_ERR; } /* receive password & username */ if (0!=scp_tcp_force_recv(c->in_sck, c->in_s->data, 8)) { log_message(s_log, LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: network error", __LINE__); return SCP_SERVER_STATE_NETWORK_ERR; } in_uint32_be(c->in_s, version); if (version!=1) { log_message(s_log, LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: version error", __LINE__); return SCP_SERVER_STATE_VERSION_ERR; } in_uint32_be(c->in_s, size); if (size<12) { log_message(s_log, LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: size error", __LINE__); return SCP_SERVER_STATE_SIZE_ERR; } init_stream(c->in_s, c->in_s->size); if (0!=scp_tcp_force_recv(c->in_sck, c->in_s->data, (size-8))) { log_message(s_log, LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: network error", __LINE__); return SCP_SERVER_STATE_NETWORK_ERR; } in_uint16_be(c->in_s, cmdset); if (cmdset != SCP_COMMAND_SET_DEFAULT) { log_message(s_log, LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: sequence error", __LINE__); return SCP_SERVER_STATE_SEQUENCE_ERR; } in_uint16_be(c->in_s, cmd); if (cmd != 4) { log_message(s_log, LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: sequence error", __LINE__); return SCP_SERVER_STATE_SEQUENCE_ERR; } buf[256] = '\0'; /* reading username */ in_uint8(c->in_s, sz); buf[sz] = '\0'; in_uint8a(c->in_s, buf, sz); if (0 != scp_session_set_username(s, buf)) { scp_session_destroy(s); log_message(s_log, LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: internal error", __LINE__); return SCP_SERVER_STATE_INTERNAL_ERR; } /* reading password */ in_uint8(c->in_s, sz); buf[sz]='\0'; in_uint8a(c->in_s, buf, sz); if (0 != scp_session_set_password(s, buf)) { scp_session_destroy(s); log_message(s_log, LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: internal error", __LINE__); return SCP_SERVER_STATE_INTERNAL_ERR; } return SCP_SERVER_STATE_OK; } /* 020 */ enum SCP_SERVER_STATES_E scp_v1s_request_pwd_change(struct SCP_CONNECTION* c, char* reason, char* npw) { return SCP_SERVER_STATE_INTERNAL_ERR; } /* 023 */ enum SCP_SERVER_STATES_E scp_v1s_pwd_change_error(struct SCP_CONNECTION* c, char* error, int retry, char* npw) { return SCP_SERVER_STATE_INTERNAL_ERR; } /* 030 */ enum SCP_SERVER_STATES_E scp_v1s_connect_new_session(struct SCP_CONNECTION* c, SCP_DISPLAY d) { /* send password request */ tui32 version=1; tui32 size=14; tui16 cmd=30; init_stream(c->out_s, c->out_s->size); out_uint32_be(c->out_s, version); /* version */ out_uint32_be(c->out_s, size); /* size */ out_uint16_be(c->out_s, SCP_COMMAND_SET_DEFAULT); /* cmdset */ out_uint16_be(c->out_s, cmd); /* cmd */ out_uint16_be(c->out_s, d); /* display */ if (0!=scp_tcp_force_send(c->in_sck, c->out_s->data, 14)) { log_message(s_log, LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: network error", __LINE__); return SCP_SERVER_STATE_NETWORK_ERR; } return SCP_SERVER_STATE_OK; } /* 032 */ enum SCP_SERVER_STATES_E scp_v1s_connection_error(struct SCP_CONNECTION* c, char* error) { tui16 len; len = g_strlen(error); init_stream(c->out_s,c->out_s->size); out_uint32_be(c->out_s, 1); /* packet size: 4 + 4 + 2 + 2 + len */ /* version + size + cmdset + cmd */ out_uint32_be(c->out_s, (12 + len)); out_uint16_be(c->out_s, SCP_COMMAND_SET_DEFAULT); out_uint16_be(c->out_s, SCP_CMD_CONN_ERROR); if (0 != scp_tcp_force_send(c->in_sck, c->out_s->data, (12 + len))) { return SCP_SERVER_STATE_NETWORK_ERR; } return SCP_SERVER_STATE_END; } /* 040 */ enum SCP_SERVER_STATES_E scp_v1s_list_sessions(struct SCP_CONNECTION* c, int sescnt, struct SCP_DISCONNECTED_SESSION* ds, SCP_SID* sid) { tui32 version=1; tui32 size=12; tui16 cmd=40; int pktcnt; int idx; int sidx; int pidx; struct SCP_DISCONNECTED_SESSION* cds; /* first we send a notice that we have some disconnected sessions */ init_stream(c->out_s, c->out_s->size); out_uint32_be(c->out_s, version); /* version */ out_uint32_be(c->out_s, size); /* size */ out_uint16_be(c->out_s, SCP_COMMAND_SET_DEFAULT); /* cmdset */ out_uint16_be(c->out_s, cmd); /* cmd */ if (0!=scp_tcp_force_send(c->in_sck, c->out_s->data, size)) { log_message(s_log, LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: network error", __LINE__); return SCP_SERVER_STATE_NETWORK_ERR; } /* then we wait for client ack */ #warning maybe this message could say if the session should be resized on #warning server side or client side init_stream(c->in_s, c->in_s->size); if (0!=scp_tcp_force_recv(c->in_sck, c->in_s->data, 8)) { log_message(s_log, LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: network error", __LINE__); return SCP_SERVER_STATE_NETWORK_ERR; } in_uint32_be(c->in_s, version); if (version!=1) { log_message(s_log, LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: version error", __LINE__); return SCP_SERVER_STATE_VERSION_ERR; } in_uint32_be(c->in_s, size); if (size<12) { log_message(s_log, LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: size error", __LINE__); return SCP_SERVER_STATE_SIZE_ERR; } init_stream(c->in_s, c->in_s->size); if (0!=scp_tcp_force_recv(c->in_sck, c->in_s->data, (size-8))) { log_message(s_log, LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: network error", __LINE__); return SCP_SERVER_STATE_NETWORK_ERR; } in_uint16_be(c->in_s, cmd); if (cmd != SCP_COMMAND_SET_DEFAULT) { log_message(s_log, LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: sequence error", __LINE__); return SCP_SERVER_STATE_SEQUENCE_ERR; } in_uint16_be(c->in_s, cmd); if (cmd != 41) { log_message(s_log, LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: sequence error", __LINE__); return SCP_SERVER_STATE_SEQUENCE_ERR; } /* calculating the number of packets to send */ pktcnt=sescnt/SCP_SERVER_MAX_LIST_SIZE; if ((sescnt%SCP_SERVER_MAX_LIST_SIZE)!=0) { pktcnt++; } for (idx=0; idxout_s, c->out_s->size); /* size: ver+size+cmdset+cmd+sescnt+continue+count */ size=4+4+2+2+4+1+1; /* header */ cmd=42; s_push_layer(c->out_s, channel_hdr, 8); out_uint16_be(c->out_s, SCP_COMMAND_SET_DEFAULT); out_uint16_be(c->out_s, cmd); /* session count */ out_uint32_be(c->out_s, sescnt); /* setting the continue flag */ if ((idx+1)*SCP_SERVER_MAX_LIST_SIZE >= sescnt) { out_uint8(c->out_s, 0); /* setting session count for this packet */ pidx=sescnt-(idx*SCP_SERVER_MAX_LIST_SIZE); out_uint8(c->out_s, pidx); } else { out_uint8(c->out_s, 1); /* setting session count for this packet */ pidx=SCP_SERVER_MAX_LIST_SIZE; out_uint8(c->out_s, pidx); } /* adding session descriptors */ for (sidx=0; sidxout_s, cds->SID); /* session id */ out_uint8(c->out_s, cds->type); out_uint16_be(c->out_s, cds->height); out_uint16_be(c->out_s, cds->width); out_uint8(c->out_s, cds->bpp); out_uint8(c->out_s, cds->idle_days); out_uint8(c->out_s, cds->idle_hours); out_uint8(c->out_s, cds->idle_minutes); size += 13; out_uint16_be(c->out_s, cds->conn_year); out_uint8(c->out_s, cds->conn_month); out_uint8(c->out_s, cds->conn_day); out_uint8(c->out_s, cds->conn_hour); out_uint8(c->out_s, cds->conn_minute); out_uint8(c->out_s, cds->addr_type); size += 7; if (cds->addr_type == SCP_ADDRESS_TYPE_IPV4) { in_uint32_be(c->out_s, cds->ipv4addr); size += 4; } else if (cds->addr_type == SCP_ADDRESS_TYPE_IPV6) { in_uint8a(c->out_s, cds->ipv6addr, 16); size += 16; } } s_pop_layer(c->out_s, channel_hdr); out_uint32_be(c->out_s, version); out_uint32_be(c->out_s, size); if (0 != scp_tcp_force_send(c->in_sck, c->out_s->data, size)) { log_message(s_log, LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: network error", __LINE__); return SCP_SERVER_STATE_NETWORK_ERR; } } /* we get the response */ init_stream(c->in_s, c->in_s->size); if (0!=scp_tcp_force_recv(c->in_sck, c->in_s->data, (8))) { log_message(s_log, LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: network error", __LINE__); return SCP_SERVER_STATE_NETWORK_ERR; } in_uint32_be(c->in_s, version); if (version != 1) { log_message(s_log, LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: version error", __LINE__); return SCP_SERVER_STATE_VERSION_ERR; } in_uint32_be(c->in_s, size); if (size < 12) { log_message(s_log, LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: size error", __LINE__); return SCP_SERVER_STATE_SIZE_ERR; } /* rest of the packet */ init_stream(c->in_s, c->in_s->size); if (0!=scp_tcp_force_recv(c->in_sck, c->in_s->data, (size-8))) { log_message(s_log, LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: network error", __LINE__); return SCP_SERVER_STATE_NETWORK_ERR; } in_uint16_be(c->in_s, cmd); if (cmd != SCP_COMMAND_SET_DEFAULT) { log_message(s_log, LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: sequence error", __LINE__); return SCP_SERVER_STATE_SEQUENCE_ERR; } in_uint16_be(c->in_s, cmd); if (cmd == 43) { /* select session */ in_uint32_be(c->in_s, (*sid)); /* checking sid value */ for (idx=0; idxout_s, c->out_s->size); /* header */ out_uint32_be(c->out_s, version); out_uint32_be(c->out_s, size); out_uint16_be(c->out_s, SCP_COMMAND_SET_DEFAULT); out_uint16_be(c->out_s, cmd); /* session data */ out_uint16_be(c->out_s, d); /* session display */ /*out_uint8(c->out_s, ds->type); out_uint16_be(c->out_s, ds->height); out_uint16_be(c->out_s, ds->width); out_uint8(c->out_s, ds->bpp); out_uint8(c->out_s, ds->idle_days); out_uint8(c->out_s, ds->idle_hours); out_uint8(c->out_s, ds->idle_minutes);*/ /* these last three are not really needed... */ if (0!=scp_tcp_force_send(c->in_sck, c->out_s->data, size)) { log_message(s_log, LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: network error", __LINE__); return SCP_SERVER_STATE_NETWORK_ERR; } return SCP_SERVER_STATE_OK; } #endif xrdp-0.6.0/sesman/libscp/libscp_v1s.h000066400000000000000000000050641203155130500174520ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2005-2010 */ /** * * @file libscp_v1s.h * @brief libscp version 1 server api declarations * @author Simone Fedele * */ #ifndef LIBSCP_V1S_H #define LIBSCP_V1S_H #include "libscp.h" /* server API */ /** * * @brief processes the stream using scp version 1 * @param c connection descriptor * @param s pointer to session descriptor pointer * @param skipVchk if set to !0 skips the version control (to be used after * scp_vXs_accept() ) * * this function places in *s the address of a newely allocated SCP_SESSION structure * that should be free()d */ enum SCP_SERVER_STATES_E scp_v1s_accept(struct SCP_CONNECTION* c, struct SCP_SESSION** s, int skipVchk); /** * * @brief denies connection to sesman * @param c connection descriptor * @param reason pointer to a string containinge the reason for denying connection * */ /* 002 */ enum SCP_SERVER_STATES_E scp_v1s_deny_connection(struct SCP_CONNECTION* c, char* reason); enum SCP_SERVER_STATES_E scp_v1s_request_password(struct SCP_CONNECTION* c, struct SCP_SESSION* s, char* reason); /* 020 */ enum SCP_SERVER_STATES_E scp_v1s_request_pwd_change(struct SCP_CONNECTION* c, char* reason, char* npw); /* 023 */ enum SCP_SERVER_STATES_E scp_v1s_pwd_change_error(struct SCP_CONNECTION* c, char* error, int retry, char* npw); /* 030 */ enum SCP_SERVER_STATES_E scp_v1s_connect_new_session(struct SCP_CONNECTION* c, SCP_DISPLAY d); /* 032 */ enum SCP_SERVER_STATES_E scp_v1s_connection_error(struct SCP_CONNECTION* c, char* error); /* 040 */ enum SCP_SERVER_STATES_E scp_v1s_list_sessions(struct SCP_CONNECTION* c, int sescnt, struct SCP_DISCONNECTED_SESSION* ds, SCP_SID* sid); /* 046 was: 031 struct SCP_DISCONNECTED_SESSION* ds, */ enum SCP_SERVER_STATES_E scp_v1s_reconnect_session(struct SCP_CONNECTION* c, SCP_DISPLAY d); #endif xrdp-0.6.0/sesman/libscp/libscp_v1s_mng.c000066400000000000000000000217101203155130500203020ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2005-2010 */ /** * * @file libscp_v1s_mng.c * @brief libscp version 1 server api code - session management * @author Simone Fedele * */ #ifndef LIBSCP_V1S_MNG_C #define LIBSCP_V1S_MNG_C #include "libscp_v1s_mng.h" extern struct log_config* s_log; static enum SCP_SERVER_STATES_E _scp_v1s_mng_check_response(struct SCP_CONNECTION* c, struct SCP_SESSION* s); /* server API */ enum SCP_SERVER_STATES_E scp_v1s_mng_accept(struct SCP_CONNECTION* c, struct SCP_SESSION** s) { struct SCP_SESSION* session; tui32 ipaddr; tui16 cmd; tui8 sz; char buf[257]; /* reading command */ in_uint16_be(c->in_s, cmd); if (cmd != 1) /* manager login */ { return SCP_SERVER_STATE_SEQUENCE_ERR; } session = scp_session_create(); if (0 == session) { return SCP_SERVER_STATE_INTERNAL_ERR; } scp_session_set_version(session, 1); scp_session_set_type(session, SCP_SESSION_TYPE_MANAGE); /* reading username */ in_uint8(c->in_s, sz); buf[sz]='\0'; in_uint8a(c->in_s, buf, sz); if (0 != scp_session_set_username(session, buf)) { scp_session_destroy(session); return SCP_SERVER_STATE_INTERNAL_ERR; } /* reading password */ in_uint8(c->in_s, sz); buf[sz]='\0'; in_uint8a(c->in_s, buf, sz); if (0 != scp_session_set_password(session, buf)) { scp_session_destroy(session); return SCP_SERVER_STATE_INTERNAL_ERR; } /* reading remote address */ in_uint8(c->in_s, sz); if (sz == SCP_ADDRESS_TYPE_IPV4) { in_uint32_be(c->in_s, ipaddr); scp_session_set_addr(session, SCP_ADDRESS_TYPE_IPV4_BIN, &ipaddr); } else if (sz == SCP_ADDRESS_TYPE_IPV6) { in_uint8a(c->in_s, buf, 16); scp_session_set_addr(session, SCP_ADDRESS_TYPE_IPV6_BIN, buf); } /* reading hostname */ in_uint8(c->in_s, sz); buf[sz]='\0'; in_uint8a(c->in_s, buf, sz); if (0 != scp_session_set_hostname(session, buf)) { scp_session_destroy(session); return SCP_SERVER_STATE_INTERNAL_ERR; } /* returning the struct */ (*s)=session; return SCP_SERVER_STATE_START_MANAGE; } /* 002 */ enum SCP_SERVER_STATES_E scp_v1s_mng_allow_connection(struct SCP_CONNECTION* c, struct SCP_SESSION* s) { init_stream(c->out_s,c->out_s->size); out_uint32_be(c->out_s, 1); /* packet size: 4 + 4 + 2 + 2 */ /* version + size + cmdset + cmd */ out_uint32_be(c->out_s, 12); out_uint16_be(c->out_s, SCP_COMMAND_SET_MANAGE); out_uint16_be(c->out_s, SCP_CMD_MNG_LOGIN_ALLOW); if (0 != scp_tcp_force_send(c->in_sck, c->out_s->data, 12)) { return SCP_SERVER_STATE_NETWORK_ERR; } return _scp_v1s_mng_check_response(c, s); } /* 003 */ enum SCP_SERVER_STATES_E scp_v1s_mng_deny_connection(struct SCP_CONNECTION* c, char* reason) { int rlen; init_stream(c->out_s,c->out_s->size); /* forcing message not to exceed 64k */ rlen = g_strlen(reason); if (rlen > 65535) { rlen = 65535; } out_uint32_be(c->out_s, 1); /* packet size: 4 + 4 + 2 + 2 + 2 + strlen(reason)*/ /* version + size + cmdset + cmd + msglen + msg */ out_uint32_be(c->out_s, rlen+14); out_uint16_be(c->out_s, SCP_COMMAND_SET_MANAGE); out_uint16_be(c->out_s, SCP_CMD_MNG_LOGIN_DENY); out_uint16_be(c->out_s, rlen); out_uint8p(c->out_s, reason, rlen); if (0!=scp_tcp_force_send(c->in_sck, c->out_s->data, rlen+14)) { return SCP_SERVER_STATE_NETWORK_ERR; } return SCP_SERVER_STATE_END; } /* 006 */ enum SCP_SERVER_STATES_E scp_v1s_mng_list_sessions(struct SCP_CONNECTION* c, struct SCP_SESSION* s, int sescnt, struct SCP_DISCONNECTED_SESSION* ds) { tui32 version = 1; tui32 size = 12; tui16 cmd = SCP_CMD_MNG_LIST; int pktcnt; int idx; int sidx; int pidx; struct SCP_DISCONNECTED_SESSION* cds; /* calculating the number of packets to send */ pktcnt=sescnt/SCP_SERVER_MAX_LIST_SIZE; if ((sescnt%SCP_SERVER_MAX_LIST_SIZE)!=0) { pktcnt++; } for (idx=0; idxout_s, c->out_s->size); /* size: ver+size+cmdset+cmd+sescnt+continue+count */ size=4+4+2+2+4+1+1; /* header */ s_push_layer(c->out_s, channel_hdr, 8); out_uint16_be(c->out_s, SCP_COMMAND_SET_MANAGE); out_uint16_be(c->out_s, cmd); /* session count */ out_uint32_be(c->out_s, sescnt); /* setting the continue flag */ if ((idx+1)*SCP_SERVER_MAX_LIST_SIZE >= sescnt) { out_uint8(c->out_s, 0); /* setting session count for this packet */ pidx=sescnt-(idx*SCP_SERVER_MAX_LIST_SIZE); out_uint8(c->out_s, pidx); } else { out_uint8(c->out_s, 1); /* setting session count for this packet */ pidx=SCP_SERVER_MAX_LIST_SIZE; out_uint8(c->out_s, pidx); } /* adding session descriptors */ for (sidx=0; sidxout_s, cds->SID); /* session id */ out_uint8(c->out_s, cds->type); out_uint16_be(c->out_s, cds->height); out_uint16_be(c->out_s, cds->width); out_uint8(c->out_s, cds->bpp); out_uint8(c->out_s, cds->idle_days); out_uint8(c->out_s, cds->idle_hours); out_uint8(c->out_s, cds->idle_minutes); size += 13; out_uint16_be(c->out_s, cds->conn_year); out_uint8(c->out_s, cds->conn_month); out_uint8(c->out_s, cds->conn_day); out_uint8(c->out_s, cds->conn_hour); out_uint8(c->out_s, cds->conn_minute); out_uint8(c->out_s, cds->addr_type); size += 7; if (cds->addr_type == SCP_ADDRESS_TYPE_IPV4) { in_uint32_be(c->out_s, cds->ipv4addr); size += 4; } else if (cds->addr_type == SCP_ADDRESS_TYPE_IPV6) { in_uint8a(c->out_s, cds->ipv6addr, 16); size += 16; } } s_pop_layer(c->out_s, channel_hdr); out_uint32_be(c->out_s, version); out_uint32_be(c->out_s, size); if (0!=scp_tcp_force_send(c->in_sck, c->out_s->data, size)) { log_message(s_log, LOG_LEVEL_WARNING, "[v1s_mng:%d] connection aborted: network error", __LINE__); return SCP_SERVER_STATE_NETWORK_ERR; } } return _scp_v1s_mng_check_response(c, s); } static enum SCP_SERVER_STATES_E _scp_v1s_mng_check_response(struct SCP_CONNECTION* c, struct SCP_SESSION* s) { tui32 version; tui32 size; tui16 cmd; // tui8 dim; // char buf[257]; init_stream(c->in_s, c->in_s->size); if (0 != scp_tcp_force_recv(c->in_sck, c->in_s->data, 8)) { log_message(s_log, LOG_LEVEL_WARNING, "[v1s_mng:%d] connection aborted: network error", __LINE__); return SCP_SERVER_STATE_NETWORK_ERR; } in_uint32_be(c->in_s, version); if (version != 1) { log_message(s_log, LOG_LEVEL_WARNING, "[v1s_mng:%d] connection aborted: version error", __LINE__); return SCP_SERVER_STATE_VERSION_ERR; } in_uint32_be(c->in_s, size); init_stream(c->in_s, c->in_s->size); /* read the rest of the packet */ if (0 != scp_tcp_force_recv(c->in_sck, c->in_s->data, size - 8)) { log_message(s_log, LOG_LEVEL_WARNING, "[v1s_mng:%d] connection aborted: network error", __LINE__); return SCP_SERVER_STATE_NETWORK_ERR; } in_uint16_be(c->in_s, cmd); if (cmd != SCP_COMMAND_SET_MANAGE) { log_message(s_log, LOG_LEVEL_WARNING, "[v1s_mng:%d] connection aborted: sequence error", __LINE__); return SCP_SERVER_STATE_SEQUENCE_ERR; } in_uint16_be(c->in_s, cmd); if (cmd == SCP_CMD_MNG_LIST_REQ) /* request session list */ { log_message(s_log, LOG_LEVEL_INFO, "[v1s_mng:%d] request session list", __LINE__); return SCP_SERVER_STATE_MNG_LISTREQ; } else if (cmd == SCP_CMD_MNG_ACTION) /* execute an action */ { /*in_uint8(c->in_s, dim); buf[dim]='\0'; in_uint8a(c->in_s, buf, dim); scp_session_set_errstr(s, buf);*/ log_message(s_log, LOG_LEVEL_INFO, "[v1s_mng:%d] action request", __LINE__); return SCP_SERVER_STATE_MNG_ACTION; } /* else if (cmd == 20) / * password change * / { in_uint16_be(c->in_s, s->display); return SCP_SERVER_STATE_OK; } else if (cmd == 40) / * session list * / { return SCP_SERVER_STATE_SESSION_LIST; }*/ log_message(s_log, LOG_LEVEL_WARNING, "[v1s_mng:%d] connection aborted: sequence error", __LINE__); return SCP_SERVER_STATE_SEQUENCE_ERR; } #endif xrdp-0.6.0/sesman/libscp/libscp_v1s_mng.h000066400000000000000000000041521203155130500203100ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2005-2010 */ /** * * @file libscp_v1s_mng.h * @brief libscp version 1 server api declarations - session management * @author Simone Fedele * */ #ifndef LIBSCP_V1S_MNG_H #define LIBSCP_V1S_MNG_H #include "libscp.h" /* server API */ /** * * @brief processes the stream using scp version 1 * @param c connection descriptor * @param s pointer to session descriptor pointer * * this function places in *s the address of a newely allocated SCP_SESSION structure * that should be free()d */ enum SCP_SERVER_STATES_E scp_v1s_mng_accept(struct SCP_CONNECTION* c, struct SCP_SESSION** s); /** * * @brief allows connection to sesman * @param c connection descriptor * */ /* 002 */ enum SCP_SERVER_STATES_E scp_v1s_mng_allow_connection(struct SCP_CONNECTION* c, struct SCP_SESSION* s); /** * * @brief denies connection to sesman * @param c connection descriptor * @param reason pointer to a string containinge the reason for denying connection * */ /* 003 */ enum SCP_SERVER_STATES_E scp_v1s_mng_deny_connection(struct SCP_CONNECTION* c, char* reason); /** * * @brief sends session list * @param c connection descriptor * */ /* 006 */ enum SCP_SERVER_STATES_E scp_v1s_mng_list_sessions(struct SCP_CONNECTION* c, struct SCP_SESSION* s, int sescnt, struct SCP_DISCONNECTED_SESSION* ds); // SCP_SID* sid); #endif xrdp-0.6.0/sesman/libscp/libscp_vX.c000066400000000000000000000025541203155130500173320ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2005-2010 */ /** * * @file libscp_vX.c * @brief libscp version neutral code * @author Simone Fedele * */ #include "libscp_vX.h" /* server API */ enum SCP_SERVER_STATES_E scp_vXs_accept(struct SCP_CONNECTION* c, struct SCP_SESSION** s) { tui32 version; /* reading version and packet size */ if (0!=scp_tcp_force_recv(c->in_sck, c->in_s->data, 8)) { return SCP_SERVER_STATE_NETWORK_ERR; } in_uint32_be(c->in_s, version); if (version == 0) { return scp_v0s_accept(c, s, 1); } else if (version == 1) { return scp_v1s_accept(c, s, 1); } return SCP_SERVER_STATE_VERSION_ERR; } xrdp-0.6.0/sesman/libscp/libscp_vX.h000066400000000000000000000025331203155130500173340ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2005-2010 */ /** * * @file libscp_vX.h * @brief libscp version neutral code header * @author Simone Fedele * */ #ifndef LIBSCP_VX_H #define LIBSCP_VX_H #include "libscp_types.h" #include "libscp_v0.h" #include "libscp_v1s.h" /* server API */ /** * * @brief version neutral server accept function * @param c connection descriptor * @param s session descriptor pointer address. * it will return a newely allocated descriptor. * It this memory needs to be g_free()d * */ enum SCP_SERVER_STATES_E scp_vXs_accept(struct SCP_CONNECTION* c, struct SCP_SESSION** s); #endif xrdp-0.6.0/sesman/lock.c000066400000000000000000000064141203155130500150540ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2005-2010 session manager linux only */ #include "sesman.h" extern struct config_sesman* g_cfg; /* in sesman.c */ static tbus g_sync_mutex = 0; static tbus g_lock_chain = 0; static tbus g_sync_sem = 0; static tbus g_lock_socket = 0; /******************************************************************************/ void APP_CC lock_init(void) { g_sync_mutex = tc_mutex_create(); g_lock_chain = tc_mutex_create(); g_sync_sem = tc_sem_create(0); g_lock_socket = tc_sem_create(1); } /******************************************************************************/ void APP_CC lock_deinit(void) { tc_mutex_delete(g_sync_mutex); tc_mutex_delete(g_lock_chain); tc_sem_delete(g_sync_sem); tc_sem_delete(g_lock_socket); } /******************************************************************************/ void APP_CC lock_chain_acquire(void) { /* lock the chain */ LOG_DBG(&(g_cfg->log), "lock_chain_acquire()"); tc_mutex_lock(g_lock_chain); } /******************************************************************************/ void APP_CC lock_chain_release(void) { /* unlock the chain */ LOG_DBG(&(g_cfg->log), "lock_chain_release()"); tc_mutex_unlock(g_lock_chain); } /******************************************************************************/ void APP_CC lock_socket_acquire(void) { /* lock socket variable */ LOG_DBG(&(g_cfg->log), "lock_socket_acquire()"); tc_sem_dec(g_lock_socket); } /******************************************************************************/ void APP_CC lock_socket_release(void) { /* unlock socket variable */ LOG_DBG(&(g_cfg->log), "lock_socket_release()"); tc_sem_inc(g_lock_socket); } /******************************************************************************/ void APP_CC lock_sync_acquire(void) { /* lock sync variable */ LOG_DBG(&(g_cfg->log), "lock_sync_acquire()"); tc_mutex_lock(g_sync_mutex); } /******************************************************************************/ void APP_CC lock_sync_release(void) { /* unlock socket variable */ LOG_DBG(&(g_cfg->log), "lock_sync_release()"); tc_mutex_unlock(g_sync_mutex); } /******************************************************************************/ void APP_CC lock_sync_sem_acquire(void) { /* dec sem */ LOG_DBG(&(g_cfg->log), "lock_sync_sem_acquire()"); tc_sem_dec(g_sync_sem); } /******************************************************************************/ void APP_CC lock_sync_sem_release(void) { /* inc sem */ LOG_DBG(&(g_cfg->log), "lock_sync_sem_release()"); tc_sem_inc(g_sync_sem); } xrdp-0.6.0/sesman/lock.h000066400000000000000000000033101203155130500150510ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2005-2010 */ #ifndef LOCK_H #define LOCK_H #include "sesman.h" /** * * @brief initializes all the locks * */ void APP_CC lock_init(void); /** * * @brief cleanup all the locks * */ void APP_CC lock_deinit(void); /** * * @brief acquires the lock for the session chain * */ void APP_CC lock_chain_acquire(void); /** * * @brief releases the session chain lock * */ void APP_CC lock_chain_release(void); /** * * @brief request the socket lock * */ void APP_CC lock_socket_acquire(void); /** * * @brief releases the socket lock * */ void APP_CC lock_socket_release(void); /** * * @brief request the main sync lock * */ void APP_CC lock_sync_acquire(void); /** * * @brief releases the main sync lock * */ void APP_CC lock_sync_release(void); /** * * @brief request the sync sem lock * */ void APP_CC lock_sync_sem_acquire(void); /** * * @brief releases the sync sem lock * */ void APP_CC lock_sync_sem_release(void); #endif xrdp-0.6.0/sesman/scp.c000066400000000000000000000066601203155130500147140ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2005-2008 */ /** * * @file scp.c * @brief scp (sesman control protocol) common code * scp (sesman control protocol) common code * This code controls which version is being used and starts the * appropriate process * @author Jay Sorg, Simone Fedele * */ #include "sesman.h" extern int g_thread_sck; /* in thread.c */ extern struct config_sesman* g_cfg; /* in sesman.c */ /******************************************************************************/ void* DEFAULT_CC scp_process_start(void* sck) { struct SCP_CONNECTION scon; struct SCP_SESSION* sdata; /* making a local copy of the socket (it's on the stack) */ /* probably this is just paranoia */ scon.in_sck = g_thread_sck; LOG_DBG(&(g_cfg->log), "started scp thread on socket %d", scon.in_sck); /* unlocking g_thread_sck */ lock_socket_release(); make_stream(scon.in_s); make_stream(scon.out_s); init_stream(scon.in_s, 8192); init_stream(scon.out_s, 8192); switch (scp_vXs_accept(&scon, &(sdata))) { case SCP_SERVER_STATE_OK: if (sdata->version == 0) { /* starts processing an scp v0 connection */ LOG_DBG(&(g_cfg->log), "accept ok, go on with scp v0\n",0); scp_v0_process(&scon, sdata); } else { LOG_DBG(&(g_cfg->log), "accept ok, go on with scp v1\n",0); /*LOG_DBG(&(g_cfg->log), "user: %s\npass: %s",sdata->username, sdata->password);*/ scp_v1_process(&scon, sdata); } break; case SCP_SERVER_STATE_START_MANAGE: /* starting a management session */ log_message(&(g_cfg->log), LOG_LEVEL_WARNING, "starting a sesman management session..."); scp_v1_mng_process(&scon, sdata); break; case SCP_SERVER_STATE_VERSION_ERR: /* an unknown scp version was requested, so we shut down the */ /* connection (and log the fact) */ log_message(&(g_cfg->log), LOG_LEVEL_WARNING, "unknown protocol version specified. connection refused."); break; case SCP_SERVER_STATE_NETWORK_ERR: log_message(&(g_cfg->log), LOG_LEVEL_WARNING, "libscp network error."); break; case SCP_SERVER_STATE_SEQUENCE_ERR: log_message(&(g_cfg->log), LOG_LEVEL_WARNING, "libscp sequence error."); break; case SCP_SERVER_STATE_INTERNAL_ERR: /* internal error occurred (eg. malloc() error, ecc.) */ log_message(&(g_cfg->log), LOG_LEVEL_ERROR, "libscp internal error occurred."); break; default: log_message(&(g_cfg->log), LOG_LEVEL_ALWAYS, "unknown return from scp_vXs_accept()"); } g_tcp_close(scon.in_sck); free_stream(scon.in_s); free_stream(scon.out_s); return 0; } xrdp-0.6.0/sesman/scp.h000066400000000000000000000023121203155130500147070ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2005-2008 */ /** * * @file scp.h * @brief scp (sesman control protocol) common definitions * @author Simone Fedele * */ #ifndef SCP_H #define SCP_H #include "scp_v0.h" #include "scp_v1.h" #include "scp_v1_mng.h" /** * * @brief Starts a an scp protocol thread. * Starts a an scp protocol thread. * But does only version control.... * @param socket the connection socket * */ void* DEFAULT_CC scp_process_start(void* sck); #endif xrdp-0.6.0/sesman/scp_v0.c000066400000000000000000000064311203155130500153150ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2005-2008 */ /** * * @file scp_v0.c * @brief scp version 0 implementation * @author Jay Sorg, Simone Fedele * */ #include "sesman.h" extern struct config_sesman* g_cfg; /* in sesman.c */ /******************************************************************************/ void DEFAULT_CC scp_v0_process(struct SCP_CONNECTION* c, struct SCP_SESSION* s) { int display = 0; tbus data; struct session_item* s_item; data = auth_userpass(s->username, s->password); if (data) { s_item = session_get_bydata(s->username, s->width, s->height, s->bpp, s->type); if (s_item != 0) { display = s_item->display; if (0 != s->client_ip) { log_message(&(g_cfg->log), LOG_LEVEL_INFO, "++ reconnected session: username %s, display :%d.0, session_pid %d, ip %s", s->username, display, s_item->pid, s->client_ip); } else { log_message(&(g_cfg->log), LOG_LEVEL_INFO, "++ reconnected session: username %s, display :%d.0, session_pid %d", s->username, display, s_item->pid); } auth_end(data); /* don't set data to null here */ } else { LOG_DBG(&(g_cfg->log), "pre auth"); if (1 == access_login_allowed(s->username)) { if (0 != s->client_ip) { log_message(&(g_cfg->log), LOG_LEVEL_INFO, "++ created session (access granted): username %s, ip %s", s->username, s->client_ip); } else { log_message(&(g_cfg->log), LOG_LEVEL_INFO, "++ created session (access granted): username %s", s->username); } if (SCP_SESSION_TYPE_XVNC == s->type) { log_message(&(g_cfg->log), LOG_LEVEL_INFO, "starting Xvnc session..."); display = session_start(s->width, s->height, s->bpp, s->username, s->password, data, SESMAN_SESSION_TYPE_XVNC, s->domain, s->program, s->directory, s->client_ip); } else { log_message(&(g_cfg->log), LOG_LEVEL_INFO, "starting X11rdp session..."); display = session_start(s->width, s->height, s->bpp, s->username, s->password, data, SESMAN_SESSION_TYPE_XRDP, s->domain, s->program, s->directory, s->client_ip); } } else { display = 0; } } if (display == 0) { auth_end(data); scp_v0s_deny_connection(c); } else { scp_v0s_allow_connection(c, display); } } else { scp_v0s_deny_connection(c); } } xrdp-0.6.0/sesman/scp_v0.h000066400000000000000000000022341203155130500153170ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2005-2008 */ /** * * @file scp_v0.h * @brief scp version 0 declarations * @author Simone Fedele * */ #ifndef SCP_V0_H #define SCP_V0_H #include "libscp.h" /** * * @brief processes the stream using scp version 0 * @param in_sck connection socket * @param in_s input stream * @param out_s output stream * */ void DEFAULT_CC scp_v0_process(struct SCP_CONNECTION* c, struct SCP_SESSION* s); #endif xrdp-0.6.0/sesman/scp_v1.c000066400000000000000000000162641203155130500153230ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2005-2008 */ /** * * @file scp_v1.c * @brief scp version 1 implementation * @author Jay Sorg, Simone Fedele * */ #include "sesman.h" //#include "libscp_types.h" #include "libscp.h" extern struct config_sesman* g_cfg; /* in sesman.c */ static void parseCommonStates(enum SCP_SERVER_STATES_E e, char* f); /******************************************************************************/ void DEFAULT_CC scp_v1_process(struct SCP_CONNECTION* c, struct SCP_SESSION* s) { long data; int display; int retries; int current_try; enum SCP_SERVER_STATES_E e; struct SCP_DISCONNECTED_SESSION* slist; struct session_item* sitem; int scount; SCP_SID sid; retries = g_cfg->sec.login_retry; current_try = retries; data = auth_userpass(s->username, s->password); /*LOG_DBG("user: %s\npass: %s", s->username, s->password);*/ while ((!data) && ((retries == 0) || (current_try > 0))) { LOG_DBG(&(g_cfg->log), "data %d - retry %d - currenttry %d - expr %d", data, retries, current_try, ((!data) && ((retries==0) || (current_try>0)))); e=scp_v1s_request_password(c,s,"Wrong username and/or password"); switch (e) { case SCP_SERVER_STATE_OK: /* all ok, we got new username and password */ data = auth_userpass(s->username, s->password); /* one try less */ if (current_try > 0) { current_try--; } break; default: /* we check the other errors */ parseCommonStates(e, "scp_v1s_list_sessions()"); scp_session_destroy(s); return; //break; } } if (!data) { scp_v1s_deny_connection(c, "Login failed"); log_message(&(g_cfg->log), LOG_LEVEL_INFO, "Login failed for user %s. Connection terminated", s->username); scp_session_destroy(s); return; } /* testing if login is allowed*/ if (0 == access_login_allowed(s->username)) { scp_v1s_deny_connection(c, "Access to Terminal Server not allowed."); log_message(&(g_cfg->log), LOG_LEVEL_INFO, "User %s not allowed on TS. Connection terminated", s->username); scp_session_destroy(s); return; } //check if we need password change /* list disconnected sessions */ slist = session_get_byuser(s->username, &scount, SESMAN_SESSION_STATUS_DISCONNECTED); if (scount == 0) { /* no disconnected sessions - start a new one */ if (0 != s->client_ip) { log_message(&(g_cfg->log), LOG_LEVEL_INFO, "++ created session (access granted): username %s, ip %s", s->username, s->client_ip); } else { log_message(&(g_cfg->log), LOG_LEVEL_INFO, "++ created session (access granted): username %s", s->username); } if (SCP_SESSION_TYPE_XVNC == s->type) { log_message(&(g_cfg->log), LOG_LEVEL_INFO, "starting Xvnc session..."); display = session_start(s->width, s->height, s->bpp, s->username, s->password, data, SESMAN_SESSION_TYPE_XVNC, s->domain, s->program, s->directory, s->client_ip); } else { log_message(&(g_cfg->log), LOG_LEVEL_INFO, "starting X11rdp session..."); display = session_start(s->width, s->height, s->bpp, s->username, s->password, data, SESMAN_SESSION_TYPE_XRDP, s->domain, s->program, s->directory, s->client_ip); } e = scp_v1s_connect_new_session(c, display); switch (e) { case SCP_SERVER_STATE_OK: /* all ok, we got new username and password */ break; default: /* we check the other errors */ parseCommonStates(e, "scp_v1s_connect_new_session()"); break; } } else { /* one or more disconnected sessions - listing */ e = scp_v1s_list_sessions(c, scount, slist, &sid); switch (e) { /*case SCP_SERVER_STATE_FORCE_NEW:*/ /* we should check for MaxSessions */ case SCP_SERVER_STATE_SELECTION_CANCEL: log_message(&(g_cfg->log), LOG_LEVEL_INFO, "Connection cancelled after session listing"); break; case SCP_SERVER_STATE_OK: /* ok, reconnecting... */ sitem=session_get_bypid(sid); if (0==sitem) { e=scp_v1s_connection_error(c, "Internal error"); log_message(&(g_cfg->log), LOG_LEVEL_INFO, "Cannot find session item on the chain"); } else { display=sitem->display; /*e=scp_v1s_reconnect_session(c, sitem, display);*/ e=scp_v1s_reconnect_session(c, display); if (0 != s->client_ip) { log_message(&(g_cfg->log), LOG_LEVEL_INFO, "++ reconnected session: username %s, display :%d.0, session_pid %d, ip %s", s->username, display, sitem->pid, s->client_ip); } else { log_message(&(g_cfg->log), LOG_LEVEL_INFO, "++ reconnected session: username %s, display :%d.0, session_pid %d", s->username, display, sitem->pid); } g_free(sitem); } break; default: /* we check the other errors */ parseCommonStates(e, "scp_v1s_list_sessions()"); break; } g_free(slist); } /* resource management */ if ((e == SCP_SERVER_STATE_OK) && (s->rsr)) { /* here goes scp resource sharing code */ } /* cleanup */ scp_session_destroy(s); auth_end(data); } static void parseCommonStates(enum SCP_SERVER_STATES_E e, char* f) { switch (e) { case SCP_SERVER_STATE_VERSION_ERR: LOG_DBG(&(g_cfg->log), "version error") case SCP_SERVER_STATE_SIZE_ERR: /* an unknown scp version was requested, so we shut down the */ /* connection (and log the fact) */ log_message(&(g_cfg->log), LOG_LEVEL_WARNING, "protocol violation. connection closed."); break; case SCP_SERVER_STATE_NETWORK_ERR: log_message(&(g_cfg->log), LOG_LEVEL_WARNING, "libscp network error."); break; case SCP_SERVER_STATE_SEQUENCE_ERR: log_message(&(g_cfg->log), LOG_LEVEL_WARNING, "libscp sequence error."); break; case SCP_SERVER_STATE_INTERNAL_ERR: /* internal error occurred (eg. malloc() error, ecc.) */ log_message(&(g_cfg->log), LOG_LEVEL_ERROR, "libscp internal error occurred."); break; default: /* dummy: scp_v1s_request_password won't generate any other */ /* error other than the ones before */ log_message(&(g_cfg->log), LOG_LEVEL_ALWAYS, "unknown return from %s", f); break; } } xrdp-0.6.0/sesman/scp_v1.h000066400000000000000000000022071203155130500153200ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2005-2008 */ /** * * @file scp_v1.h * @brief scp version 1 declarations * @author Simone Fedele * */ #ifndef SCP_V1_H #define SCP_V1_H /** * * @brief processes the stream using scp version 1 * @param in_sck connection socket * @param in_s input stream * @param out_s output stream * */ void DEFAULT_CC scp_v1_process(struct SCP_CONNECTION* c, struct SCP_SESSION* s); #endif xrdp-0.6.0/sesman/scp_v1_mng.c000066400000000000000000000103431203155130500161540ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2005-2008 */ /** * * @file scp_v1_mng.c * @brief scp version 1 implementation - management * @author Jay Sorg, Simone Fedele * */ #include "sesman.h" #include "libscp.h" extern struct config_sesman* g_cfg; /* in sesman.c */ static void parseCommonStates(enum SCP_SERVER_STATES_E e, char* f); /******************************************************************************/ void DEFAULT_CC scp_v1_mng_process(struct SCP_CONNECTION* c, struct SCP_SESSION* s) { long data; enum SCP_SERVER_STATES_E e; struct SCP_DISCONNECTED_SESSION* slist = 0; int scount; int end = 0; data = auth_userpass(s->username, s->password); /*LOG_DBG("user: %s\npass: %s", s->username, s->password);*/ if (!data) { scp_v1s_mng_deny_connection(c, "Login failed"); log_message(&(g_cfg->log), LOG_LEVEL_INFO, "[MNG] Login failed for user %s. Connection terminated", s->username); scp_session_destroy(s); auth_end(data); return; } /* testing if login is allowed */ if (0 == access_login_mng_allowed(s->username)) { scp_v1s_mng_deny_connection(c, "Access to Terminal Server not allowed."); log_message(&(g_cfg->log), LOG_LEVEL_INFO, "[MNG] User %s not allowed on TS. Connection terminated", s->username); scp_session_destroy(s); auth_end(data); return; } e = scp_v1s_mng_allow_connection(c, s); end = 1; while (end) { switch (e) { case SCP_SERVER_STATE_MNG_ACTION: log_message(&(g_cfg->log), LOG_LEVEL_INFO, "Connection cancelled after session listing"); break; case SCP_SERVER_STATE_MNG_LISTREQ: /* list disconnected sessions */ slist = session_get_byuser(NULL, &scount, SESMAN_SESSION_STATUS_ALL); LOG_DBG(&(g_cfg->log), "sessions on TS: %d (slist: %x)", scount, slist); if (0 == slist) { // e=scp_v1s_connection_error(c, "Internal error"); log_message(&(g_cfg->log), LOG_LEVEL_INFO, "No sessions on Terminal Server"); end = 0; } else { e = scp_v1s_mng_list_sessions(c, s, scount, slist); g_free(slist); } break; default: /* we check the other errors */ parseCommonStates(e, "scp_v1s_mng_list_sessions()"); end = 0; break; } } /* cleanup */ scp_session_destroy(s); auth_end(data); } static void parseCommonStates(enum SCP_SERVER_STATES_E e, char* f) { switch (e) { case SCP_SERVER_STATE_VERSION_ERR: LOG_DBG(&(g_cfg->log), "version error") case SCP_SERVER_STATE_SIZE_ERR: /* an unknown scp version was requested, so we shut down the */ /* connection (and log the fact) */ log_message(&(g_cfg->log), LOG_LEVEL_WARNING, "protocol violation. connection closed."); break; case SCP_SERVER_STATE_NETWORK_ERR: log_message(&(g_cfg->log), LOG_LEVEL_WARNING, "libscp network error."); break; case SCP_SERVER_STATE_SEQUENCE_ERR: log_message(&(g_cfg->log), LOG_LEVEL_WARNING, "libscp sequence error."); break; case SCP_SERVER_STATE_INTERNAL_ERR: /* internal error occurred (eg. malloc() error, ecc.) */ log_message(&(g_cfg->log), LOG_LEVEL_ERROR, "libscp internal error occurred."); break; default: /* dummy: scp_v1s_request_password won't generate any other */ /* error other than the ones before */ log_message(&(g_cfg->log), LOG_LEVEL_ALWAYS, "unknown return from %s", f); break; } } xrdp-0.6.0/sesman/scp_v1_mng.h000066400000000000000000000022361203155130500161630ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2005-2008 */ /** * * @file scp_v1.h * @brief scp version 1 declarations - management * @author Simone Fedele * */ #ifndef SCP_V1_MNG_H #define SCP_V1_MNG_H /** * * @brief processes the stream using scp version 1 * @param in_sck connection socket * @param in_s input stream * @param out_s output stream * */ void DEFAULT_CC scp_v1_mng_process(struct SCP_CONNECTION* c, struct SCP_SESSION* s); #endif xrdp-0.6.0/sesman/sesman.c000066400000000000000000000226751203155130500154210ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2005-2008 */ /** * * @file sesman.c * @brief Main program file * @author Jay Sorg * */ #include "sesman.h" int g_sck; int g_pid; unsigned char g_fixedkey[8] = { 23, 82, 107, 6, 35, 78, 88, 7 }; struct config_sesman* g_cfg; /* defined in config.h */ tbus g_term_event = 0; tbus g_sync_event = 0; extern int g_thread_sck; /* in thread.c */ /******************************************************************************/ /** * * @brief Starts sesman main loop * */ static void DEFAULT_CC sesman_main_loop(void) { int in_sck; int error; int robjs_count; int cont; tbus sck_obj; tbus robjs[8]; /*main program loop*/ log_message(&(g_cfg->log), LOG_LEVEL_INFO, "listening..."); g_sck = g_tcp_socket(); g_tcp_set_non_blocking(g_sck); error = scp_tcp_bind(g_sck, g_cfg->listen_address, g_cfg->listen_port); if (error == 0) { error = g_tcp_listen(g_sck); if (error == 0) { sck_obj = g_create_wait_obj_from_socket(g_sck, 0); cont = 1; while (cont) { /* build the wait obj list */ robjs_count = 0; robjs[robjs_count++] = sck_obj; robjs[robjs_count++] = g_term_event; robjs[robjs_count++] = g_sync_event; /* wait */ if (g_obj_wait(robjs, robjs_count, 0, 0, -1) != 0) { /* error, should not get here */ g_sleep(100); } if (g_is_wait_obj_set(g_term_event)) /* term */ { break; } if (g_is_wait_obj_set(g_sync_event)) /* sync */ { g_reset_wait_obj(g_sync_event); session_sync_start(); } if (g_is_wait_obj_set(sck_obj)) /* incoming connection */ { in_sck = g_tcp_accept(g_sck); if ((in_sck == -1) && g_tcp_last_error_would_block(g_sck)) { /* should not get here */ g_sleep(100); } else if (in_sck == -1) { /* error, should not get here */ break; } else { /* we've got a connection, so we pass it to scp code */ LOG_DBG(&(g_cfg->log), "new connection"); thread_scp_start(in_sck); /* todo, do we have to wait here ? */ } } } g_delete_wait_obj_from_socket(sck_obj); } else { log_message(&(g_cfg->log), LOG_LEVEL_ERROR, "listen error %d (%s)", g_get_errno(), g_get_strerror()); } } else { log_message(&(g_cfg->log), LOG_LEVEL_ERROR, "bind error on " "port '%s': %d (%s)", g_cfg->listen_port, g_get_errno(), g_get_strerror()); } g_tcp_close(g_sck); } /******************************************************************************/ int DEFAULT_CC main(int argc, char** argv) { int fd; int error; int daemon = 1; int pid; char pid_s[8]; char text[256]; char pid_file[256]; g_init("xrdp-sesman"); g_snprintf(pid_file, 255, "%s/xrdp-sesman.pid", XRDP_PID_PATH); if (1 == argc) { /* no options on command line. normal startup */ g_printf("starting sesman...\n"); daemon = 1; } else if ((2 == argc) && ((0 == g_strcasecmp(argv[1], "--nodaemon")) || (0 == g_strcasecmp(argv[1], "-nodaemon")) || (0 == g_strcasecmp(argv[1], "-n")) || (0 == g_strcasecmp(argv[1], "-ns")))) { /* starts sesman not daemonized */ g_printf("starting sesman in foregroud...\n"); daemon = 0; } else if ((2 == argc) && ((0 == g_strcasecmp(argv[1], "--help")) || (0 == g_strcasecmp(argv[1], "-help")) || (0 == g_strcasecmp(argv[1], "-h")))) { /* help screen */ g_printf("sesman - xrdp session manager\n\n"); g_printf("usage: sesman [command]\n\n"); g_printf("command can be one of the following:\n"); g_printf("-n, -ns, --nodaemon starts sesman in foreground\n"); g_printf("-k, --kill kills running sesman\n"); g_printf("-h, --help shows this help\n"); g_printf("if no command is specified, sesman is started in background"); g_deinit(); g_exit(0); } else if ((2 == argc) && ((0 == g_strcasecmp(argv[1], "--kill")) || (0 == g_strcasecmp(argv[1], "-kill")) || (0 == g_strcasecmp(argv[1], "-k")))) { /* killing running sesman */ /* check if sesman is running */ if (!g_file_exist(pid_file)) { g_printf("sesman is not running (pid file not found - %s)\n", pid_file); g_deinit(); g_exit(1); } fd = g_file_open(pid_file); if (-1 == fd) { g_printf("error opening pid file[%s]: %s\n", pid_file, g_get_strerror()); return 1; } error = g_file_read(fd, pid_s, 7); if (-1 == error) { g_printf("error reading pid file: %s\n", g_get_strerror()); g_file_close(fd); g_deinit(); g_exit(error); } g_file_close(fd); pid = g_atoi(pid_s); error = g_sigterm(pid); if (0 != error) { g_printf("error killing sesman: %s\n", g_get_strerror()); } else { g_file_delete(pid_file); } g_deinit(); g_exit(error); } else { /* there's something strange on the command line */ g_printf("sesman - xrdp session manager\n\n"); g_printf("error: invalid command line\n"); g_printf("usage: sesman [ --nodaemon | --kill | --help ]\n"); g_deinit(); g_exit(1); } if (g_file_exist(pid_file)) { g_printf("sesman is already running.\n"); g_printf("if it's not running, try removing "); g_printf(pid_file); g_printf("\n"); g_deinit(); g_exit(1); } /* reading config */ g_cfg = g_malloc(sizeof(struct config_sesman), 1); if (0 == g_cfg) { g_printf("error creating config: quitting.\n"); g_deinit(); g_exit(1); } g_cfg->log.fd = -1; /* don't use logging before reading its config */ if (0 != config_read(g_cfg)) { g_printf("error reading config: %s\nquitting.\n", g_get_strerror()); g_deinit(); g_exit(1); } /* starting logging subsystem */ error = log_start(&(g_cfg->log)); if (error != LOG_STARTUP_OK) { switch (error) { case LOG_ERROR_MALLOC: g_printf("error on malloc. cannot start logging. quitting.\n"); break; case LOG_ERROR_FILE_OPEN: g_printf("error opening log file [%s]. quitting.\n", g_cfg->log.log_file); break; } g_deinit(); g_exit(1); } /* libscp initialization */ scp_init(&(g_cfg->log)); if (daemon) { /* start of daemonizing code */ g_pid = g_fork(); if (0 != g_pid) { g_deinit(); g_exit(0); } g_file_close(0); g_file_close(1); g_file_close(2); g_file_open("/dev/null"); g_file_open("/dev/null"); g_file_open("/dev/null"); } /* initializing locks */ lock_init(); /* signal handling */ g_pid = g_getpid(); /* old style signal handling is now managed synchronously by a * separate thread. uncomment this block if you need old style * signal handling and comment out thread_sighandler_start() * going back to old style for the time being * problem with the sigaddset functions in sig.c - jts */ #if 1 g_signal_hang_up(sig_sesman_reload_cfg); /* SIGHUP */ g_signal_user_interrupt(sig_sesman_shutdown); /* SIGINT */ g_signal_kill(sig_sesman_shutdown); /* SIGKILL */ g_signal_terminate(sig_sesman_shutdown); /* SIGTERM */ g_signal_child_stop(sig_sesman_session_end); /* SIGCHLD */ #endif #if 0 thread_sighandler_start(); #endif if (daemon) { /* writing pid file */ fd = g_file_open(pid_file); if (-1 == fd) { log_message(&(g_cfg->log), LOG_LEVEL_ERROR, "error opening pid file[%s]: %s", pid_file, g_get_strerror()); log_end(&(g_cfg->log)); g_deinit(); g_exit(1); } g_sprintf(pid_s, "%d", g_pid); g_file_write(fd, pid_s, g_strlen(pid_s)); g_file_close(fd); } /* start program main loop */ log_message(&(g_cfg->log), LOG_LEVEL_ALWAYS, "starting sesman with pid %d", g_pid); /* make sure the /tmp/.X11-unix directory exist */ if (!g_directory_exist("/tmp/.X11-unix")) { g_create_dir("/tmp/.X11-unix"); g_chmod_hex("/tmp/.X11-unix", 0x1777); } g_snprintf(text, 255, "xrdp_sesman_%8.8x_main_term", g_pid); g_term_event = g_create_wait_obj(text); g_snprintf(text, 255, "xrdp_sesman_%8.8x_main_sync", g_pid); g_sync_event = g_create_wait_obj(text); sesman_main_loop(); /* clean up PID file on exit */ if (daemon) { g_file_delete(pid_file); } g_delete_wait_obj(g_term_event); g_delete_wait_obj(g_sync_event); if (!daemon) { log_end(&(g_cfg->log)); } g_deinit(); return 0; } xrdp-0.6.0/sesman/sesman.h000066400000000000000000000024401203155130500154120ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2005-2008 */ /** * * @file sesman.h * @brief Main include file * @author Jay Sorg * */ #ifndef SESMAN_H #define SESMAN_H #if defined(HAVE_CONFIG_H) #include "config_ac.h" #endif #include "d3des.h" #include "arch.h" #include "parse.h" #include "os_calls.h" #include "log.h" #include "file_loc.h" #include "env.h" #include "auth.h" #include "config.h" //#include "tcp.h" #include "sig.h" #include "session.h" #include "access.h" #include "scp.h" #include "thread.h" #include "lock.h" #include "thread_calls.h" #include "libscp.h" #endif xrdp-0.6.0/sesman/sesman.ini000066400000000000000000000011241203155130500157400ustar00rootroot00000000000000[Globals] ListenAddress=127.0.0.1 ListenPort=3350 EnableUserWindowManager=1 UserWindowManager=startwm.sh DefaultWindowManager=startwm.sh [Security] AllowRootLogin=1 MaxLoginRetry=4 TerminalServerUsers=tsusers TerminalServerAdmins=tsadmins [Sessions] X11DisplayOffset=10 MaxSessions=10 KillDisconnected=0 IdleTimeLimit=0 DisconnectedTimeLimit=0 [Logging] LogFile=/var/log/xrdp-sesman.log LogLevel=DEBUG EnableSyslog=0 SyslogLevel=DEBUG [X11rdp] param1=-bs param2=-ac param3=-nolisten param4=tcp [Xvnc] param1=-bs param2=-ac param3=-nolisten param4=tcp param5=-localhost param6=-dpi param7=96 xrdp-0.6.0/sesman/session.c000066400000000000000000000641341203155130500156120ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2005-2008 */ /** * * @file session.c * @brief Session management code * @author Jay Sorg, Simone Fedele * */ #include "sesman.h" #include "libscp_types.h" #include //#include extern tbus g_sync_event; extern unsigned char g_fixedkey[8]; extern struct config_sesman* g_cfg; /* in sesman.c */ struct session_chain* g_sessions; int g_session_count; static int g_sync_width; static int g_sync_height; static int g_sync_bpp; static char* g_sync_username; static char* g_sync_password; static char* g_sync_domain; static char* g_sync_program; static char* g_sync_directory; static char* g_sync_client_ip; static tbus g_sync_data; static tui8 g_sync_type; static int g_sync_result; /******************************************************************************/ struct session_item* DEFAULT_CC session_get_bydata(char* name, int width, int height, int bpp, int type) { struct session_chain* tmp; /*THREAD-FIX require chain lock */ lock_chain_acquire(); tmp = g_sessions; /* convert from SCP_SESSION_TYPE namespace to SESMAN_SESSION_TYPE namespace */ switch (type) { case SCP_SESSION_TYPE_XVNC: /* 0 */ type = SESMAN_SESSION_TYPE_XVNC; /* 2 */ break; case SCP_SESSION_TYPE_XRDP: /* 1 */ type = SESMAN_SESSION_TYPE_XRDP; /* 1 */ break; default: lock_chain_release(); return 0; } while (tmp != 0) { if (type == SESMAN_SESSION_TYPE_XRDP) { /* only name and bpp need to match for X11rdp, it can resize */ if (g_strncmp(name, tmp->item->name, 255) == 0 && tmp->item->bpp == bpp && tmp->item->type == type) { /*THREAD-FIX release chain lock */ lock_chain_release(); return tmp->item; } } if (g_strncmp(name, tmp->item->name, 255) == 0 && tmp->item->width == width && tmp->item->height == height && tmp->item->bpp == bpp && tmp->item->type == type) { /*THREAD-FIX release chain lock */ lock_chain_release(); return tmp->item; } tmp = tmp->next; } /*THREAD-FIX release chain lock */ lock_chain_release(); return 0; } /******************************************************************************/ /** * * @brief checks if there's a server running on a display * @param display the display to check * @return 0 if there isn't a display running, nonzero otherwise * */ static int DEFAULT_CC x_server_running_check_ports(int display) { char text[256]; int x_running; int sck; g_sprintf(text, "/tmp/.X11-unix/X%d", display); x_running = g_file_exist(text); if (!x_running) { g_sprintf(text, "/tmp/.X%d-lock", display); x_running = g_file_exist(text); } if (!x_running) /* check 59xx */ { sck = g_tcp_socket(); g_sprintf(text, "59%2.2d", display); x_running = g_tcp_bind(sck, text); g_tcp_close(sck); } if (!x_running) /* check 60xx */ { sck = g_tcp_socket(); g_sprintf(text, "60%2.2d", display); x_running = g_tcp_bind(sck, text); g_tcp_close(sck); } if (!x_running) /* check 62xx */ { sck = g_tcp_socket(); g_sprintf(text, "62%2.2d", display); x_running = g_tcp_bind(sck, text); g_tcp_close(sck); } return x_running; } /******************************************************************************/ /** * * @brief checks if there's a server running on a display * @param display the display to check * @return 0 if there isn't a display running, nonzero otherwise * */ static int DEFAULT_CC x_server_running(int display) { char text[256]; int x_running; int sck; g_sprintf(text, "/tmp/.X11-unix/X%d", display); x_running = g_file_exist(text); if (!x_running) { g_sprintf(text, "/tmp/.X%d-lock", display); x_running = g_file_exist(text); } return x_running; } /******************************************************************************/ static void DEFAULT_CC session_start_sessvc(int xpid, int wmpid, long data) { struct list * sessvc_params = (struct list *)NULL; char wmpid_str[25]; char xpid_str[25]; char exe_path[262]; int i = 0; /* initialize (zero out) local variables: */ g_memset(wmpid_str,0,sizeof(char) * 25); g_memset(xpid_str,0,sizeof(char) * 25); g_memset(exe_path,0,sizeof(char) * 262); /* new style waiting for clients */ g_sprintf(wmpid_str, "%d", wmpid); g_sprintf(xpid_str, "%d", xpid); log_message(&(g_cfg->log), LOG_LEVEL_INFO, "starting xrdp-sessvc - xpid=%s - wmpid=%s", xpid_str, wmpid_str); sessvc_params = list_create(); sessvc_params->auto_free = 1; /* building parameters */ g_snprintf(exe_path, 261, "%s/xrdp-sessvc", XRDP_SBIN_PATH); list_add_item(sessvc_params, (long)g_strdup(exe_path)); list_add_item(sessvc_params, (long)g_strdup(xpid_str)); list_add_item(sessvc_params, (long)g_strdup(wmpid_str)); list_add_item(sessvc_params, 0); /* mandatory */ /* executing sessvc */ g_execvp(exe_path, ((char**)sessvc_params->items)); /* should not get here */ log_message(&(g_cfg->log), LOG_LEVEL_ALWAYS, "error starting xrdp-sessvc - pid %d - xpid=%s - wmpid=%s", g_getpid(), xpid_str, wmpid_str); /* logging parameters */ /* no problem calling strerror for thread safety: other threads are blocked */ log_message(&(g_cfg->log), LOG_LEVEL_DEBUG, "errno: %d, description: %s", errno, g_get_strerror()); log_message(&(g_cfg->log), LOG_LEVEL_DEBUG, "execve parameter list:"); for (i = 0; i < (sessvc_params->count); i++) { log_message(&(g_cfg->log), LOG_LEVEL_DEBUG, " argv[%d] = %s", i, (char*)list_get_item(sessvc_params, i)); } list_delete(sessvc_params); /* keep the old waitpid if some error occurs during execlp */ g_waitpid(wmpid); g_sigterm(xpid); g_sigterm(wmpid); g_sleep(1000); auth_end(data); g_exit(0); } /******************************************************************************/ /* called with the main thread returns boolean */ static int APP_CC session_is_display_in_chain(int display) { struct session_chain* chain; struct session_item* item; chain = g_sessions; while (chain != 0) { item = chain->item; if (item->display == display) { return 1; } chain = chain->next; } return 0; } /******************************************************************************/ /* called with the main thread */ static int APP_CC session_get_aval_display_from_chain(void) { int display; display = g_cfg->sess.x11_display_offset; lock_chain_acquire(); while ((display - g_cfg->sess.x11_display_offset) <= g_cfg->sess.max_sessions) { if (!session_is_display_in_chain(display)) { if (!x_server_running_check_ports(display)) { lock_chain_release(); return display; } } display++; } lock_chain_release(); log_message(&(g_cfg->log), LOG_LEVEL_ERROR, "X server -- no display in range is available"); return 0; } /******************************************************************************/ static int APP_CC wait_for_xserver(int display) { int i; /* give X a bit to start */ /* wait up to 10 secs for x server to start */ i = 0; while (!x_server_running(display)) { i++; if (i > 40) { log_message(&(g_cfg->log), LOG_LEVEL_ERROR, "X server for display %d startup timeout", display); break; } g_sleep(250); } return 0; } /******************************************************************************/ /* called with the main thread */ static int APP_CC session_start_fork(int width, int height, int bpp, char* username, char* password, tbus data, tui8 type, char* domain, char* program, char* directory, char* client_ip) { int display = 0; int pid = 0; int wmpid = 0; int xpid = 0; int i = 0; char geometry[32]; char depth[32]; char screen[32]; char text[256]; char passwd_file[256]; char ** pp1 = (char **)NULL; struct session_chain * temp = (struct session_chain *)NULL; struct list * xserver_params = (struct list *)NULL; time_t ltime; struct tm stime; /* initialize (zero out) local variables: */ g_memset(<ime,0,sizeof(time_t)); g_memset(&stime,0,sizeof(struct tm)); g_memset(geometry,0,sizeof(char) * 32); g_memset(depth,0,sizeof(char) * 32); g_memset(screen,0,sizeof(char) * 32); g_memset(text,0,sizeof(char) * 256); g_memset(passwd_file,0,sizeof(char) * 256); /* check to limit concurrent sessions */ if (g_session_count >= g_cfg->sess.max_sessions) { log_message(&(g_cfg->log), LOG_LEVEL_INFO, "max concurrent session limit " "exceeded. login for user %s denied", username); return 0; } temp = (struct session_chain*)g_malloc(sizeof(struct session_chain), 0); if (temp == 0) { log_message(&(g_cfg->log), LOG_LEVEL_ERROR, "cannot create new chain " "element - user %s", username); return 0; } temp->item = (struct session_item*)g_malloc(sizeof(struct session_item), 0); if (temp->item == 0) { g_free(temp); log_message(&(g_cfg->log), LOG_LEVEL_ERROR, "cannot create new session " "item - user %s", username); return 0; } display = session_get_aval_display_from_chain(); if (display == 0) { g_free(temp->item); g_free(temp); return 0; } pid = g_fork(); if (pid == -1) { } else if (pid == 0) /* child sesman */ { auth_start_session(data, display); g_sprintf(geometry, "%dx%d", width, height); g_sprintf(depth, "%d", bpp); g_sprintf(screen, ":%d", display); wmpid = g_fork(); if (wmpid == -1) { } else if (wmpid == 0) /* child (child sesman) xserver */ { wait_for_xserver(display); env_set_user(username, 0, display); if (x_server_running(display)) { auth_set_env(data); if (directory != 0) { if (directory[0] != 0) { g_set_current_dir(directory); } } if (program != 0) { if (program[0] != 0) { g_execlp3(program, program, 0); log_message(&(g_cfg->log), LOG_LEVEL_ALWAYS, "error starting program %s for user %s - pid %d", program, username, g_getpid()); } } /* try to execute user window manager if enabled */ if (g_cfg->enable_user_wm) { g_sprintf(text,"%s/%s", g_getenv("HOME"), g_cfg->user_wm); if (g_file_exist(text)) { g_execlp3(text, g_cfg->user_wm, 0); log_message(&(g_cfg->log), LOG_LEVEL_ALWAYS,"error starting user " "wm for user %s - pid %d", username, g_getpid()); /* logging parameters */ log_message(&(g_cfg->log), LOG_LEVEL_DEBUG, "errno: %d, " "description: %s", errno, g_get_strerror()); log_message(&(g_cfg->log), LOG_LEVEL_DEBUG,"execlp3 parameter " "list:"); log_message(&(g_cfg->log), LOG_LEVEL_DEBUG, " argv[0] = %s", text); log_message(&(g_cfg->log), LOG_LEVEL_DEBUG, " argv[1] = %s", g_cfg->user_wm); } } /* if we're here something happened to g_execlp3 so we try running the default window manager */ g_sprintf(text, "%s/%s", XRDP_CFG_PATH, g_cfg->default_wm); g_execlp3(text, g_cfg->default_wm, 0); log_message(&(g_cfg->log), LOG_LEVEL_ALWAYS,"error starting default " "wm for user %s - pid %d", username, g_getpid()); /* logging parameters */ log_message(&(g_cfg->log), LOG_LEVEL_DEBUG, "errno: %d, description: " "%s", errno, g_get_strerror()); log_message(&(g_cfg->log), LOG_LEVEL_DEBUG,"execlp3 parameter list:"); log_message(&(g_cfg->log), LOG_LEVEL_DEBUG, " argv[0] = %s", text); log_message(&(g_cfg->log), LOG_LEVEL_DEBUG, " argv[1] = %s", g_cfg->default_wm); /* still a problem starting window manager just start xterm */ g_execlp3("xterm", "xterm", 0); /* should not get here */ log_message(&(g_cfg->log), LOG_LEVEL_ALWAYS,"error starting xterm " "for user %s - pid %d", username, g_getpid()); /* logging parameters */ log_message(&(g_cfg->log), LOG_LEVEL_DEBUG, "errno: %d, description: " "%s", errno, g_get_strerror()); } else { log_message(&(g_cfg->log), LOG_LEVEL_ERROR, "another Xserver is " "already active on display %d", display); } log_message(&(g_cfg->log), LOG_LEVEL_DEBUG,"aborting connection..."); g_exit(0); } else /* parent (child sesman) */ { xpid = g_fork(); if (xpid == -1) { } else if (xpid == 0) /* child */ { env_set_user(username, passwd_file, display); env_check_password_file(passwd_file, password); if (type == SESMAN_SESSION_TYPE_XVNC) { xserver_params = list_create(); xserver_params->auto_free = 1; /* these are the must have parameters */ list_add_item(xserver_params, (long)g_strdup("Xvnc")); list_add_item(xserver_params, (long)g_strdup(screen)); list_add_item(xserver_params, (long)g_strdup("-geometry")); list_add_item(xserver_params, (long)g_strdup(geometry)); list_add_item(xserver_params, (long)g_strdup("-depth")); list_add_item(xserver_params, (long)g_strdup(depth)); list_add_item(xserver_params, (long)g_strdup("-rfbauth")); list_add_item(xserver_params, (long)g_strdup(passwd_file)); /* additional parameters from sesman.ini file */ //config_read_xserver_params(SESMAN_SESSION_TYPE_XVNC, // xserver_params); list_append_list_strdup(g_cfg->vnc_params, xserver_params, 0); /* make sure it ends with a zero */ list_add_item(xserver_params, 0); pp1 = (char**)xserver_params->items; g_execvp("Xvnc", pp1); } else if (type == SESMAN_SESSION_TYPE_XRDP) { xserver_params = list_create(); xserver_params->auto_free = 1; /* these are the must have parameters */ list_add_item(xserver_params, (long)g_strdup("X11rdp")); list_add_item(xserver_params, (long)g_strdup(screen)); list_add_item(xserver_params, (long)g_strdup("-geometry")); list_add_item(xserver_params, (long)g_strdup(geometry)); list_add_item(xserver_params, (long)g_strdup("-depth")); list_add_item(xserver_params, (long)g_strdup(depth)); /* additional parameters from sesman.ini file */ //config_read_xserver_params(SESMAN_SESSION_TYPE_XRDP, // xserver_params); list_append_list_strdup(g_cfg->rdp_params, xserver_params, 0); /* make sure it ends with a zero */ list_add_item(xserver_params, 0); pp1 = (char**)xserver_params->items; g_execvp("X11rdp", pp1); } else { log_message(&(g_cfg->log), LOG_LEVEL_ALWAYS, "bad session type - " "user %s - pid %d", username, g_getpid()); g_exit(1); } /* should not get here */ log_message(&(g_cfg->log), LOG_LEVEL_ALWAYS, "error starting X server " "- user %s - pid %d", username, g_getpid()); /* logging parameters */ log_message(&(g_cfg->log), LOG_LEVEL_DEBUG, "errno: %d, description: " "%s", errno, g_get_strerror()); log_message(&(g_cfg->log), LOG_LEVEL_DEBUG, "execve parameter list: " "%d", (xserver_params)->count); for (i=0; i<(xserver_params->count); i++) { log_message(&(g_cfg->log), LOG_LEVEL_DEBUG, " argv[%d] = %s", i, (char*)list_get_item(xserver_params, i)); } list_delete(xserver_params); g_exit(1); } else /* parent (child sesman)*/ { wait_for_xserver(display); g_snprintf(text, 255, "%d", display); g_setenv("XRDP_SESSVC_DISPLAY", text, 1); g_snprintf(text, 255, ":%d.0", display); g_setenv("DISPLAY", text, 1); /* new style waiting for clients */ session_start_sessvc(xpid, wmpid, data); } } } else /* parent sesman process */ { temp->item->pid = pid; temp->item->display = display; temp->item->width = width; temp->item->height = height; temp->item->bpp = bpp; temp->item->data = data; g_strncpy(temp->item->client_ip, client_ip, 255); /* store client ip data */ g_strncpy(temp->item->name, username, 255); ltime = g_time1(); localtime_r(<ime, &stime); temp->item->connect_time.year = (tui16)(stime.tm_year + 1900); temp->item->connect_time.month = (tui8)stime.tm_mon; temp->item->connect_time.day = (tui8)stime.tm_mday; temp->item->connect_time.hour = (tui8)stime.tm_hour; temp->item->connect_time.minute = (tui8)stime.tm_min; zero_time(&(temp->item->disconnect_time)); zero_time(&(temp->item->idle_time)); temp->item->type=type; temp->item->status=SESMAN_SESSION_STATUS_ACTIVE; temp->next=g_sessions; g_sessions=temp; g_session_count++; } return display; } /******************************************************************************/ /* called by a worker thread, ask the main thread to call session_sync_start and wait till done */ int DEFAULT_CC session_start(int width, int height, int bpp, char* username, char* password, long data, tui8 type, char* domain, char* program, char* directory, char* client_ip) { int display; /* lock mutex */ lock_sync_acquire(); /* set shared vars */ g_sync_width = width; g_sync_height = height; g_sync_bpp = bpp; g_sync_username = username; g_sync_password = password; g_sync_domain = domain; g_sync_program = program; g_sync_directory = directory; g_sync_client_ip = client_ip; g_sync_data = data; g_sync_type = type; /* set event for main thread to see */ g_set_wait_obj(g_sync_event); /* wait for main thread to get done */ lock_sync_sem_acquire(); /* read result(display) from shared var */ display = g_sync_result; /* unlock mutex */ lock_sync_release(); return display; } /******************************************************************************/ /* called with the main thread */ int APP_CC session_sync_start(void) { g_sync_result = session_start_fork(g_sync_width, g_sync_height, g_sync_bpp, g_sync_username, g_sync_password, g_sync_data, g_sync_type, g_sync_domain, g_sync_program, g_sync_directory, g_sync_client_ip); lock_sync_sem_release(); return 0; } /******************************************************************************/ int DEFAULT_CC session_kill(int pid) { struct session_chain* tmp; struct session_chain* prev; /*THREAD-FIX require chain lock */ lock_chain_acquire(); tmp=g_sessions; prev=0; while (tmp != 0) { if (tmp->item == 0) { log_message(&(g_cfg->log), LOG_LEVEL_ERROR, "session descriptor for " "pid %d is null!", pid); if (prev == 0) { /* prev does no exist, so it's the first element - so we set g_sessions */ g_sessions = tmp->next; } else { prev->next = tmp->next; } /*THREAD-FIX release chain lock */ lock_chain_release(); return SESMAN_SESSION_KILL_NULLITEM; } if (tmp->item->pid == pid) { /* deleting the session */ log_message(&(g_cfg->log), LOG_LEVEL_INFO, "++ terminated session: username %s, display :%d.0, session_pid %d, ip %s", tmp->item->name, tmp->item->display, tmp->item->pid, tmp->item->client_ip); g_free(tmp->item); if (prev == 0) { /* prev does no exist, so it's the first element - so we set g_sessions */ g_sessions = tmp->next; } else { prev->next = tmp->next; } g_free(tmp); g_session_count--; /*THREAD-FIX release chain lock */ lock_chain_release(); return SESMAN_SESSION_KILL_OK; } /* go on */ prev = tmp; tmp=tmp->next; } /*THREAD-FIX release chain lock */ lock_chain_release(); return SESMAN_SESSION_KILL_NOTFOUND; } /******************************************************************************/ void DEFAULT_CC session_sigkill_all() { struct session_chain* tmp; /*THREAD-FIX require chain lock */ lock_chain_acquire(); tmp=g_sessions; while (tmp != 0) { if (tmp->item == 0) { log_message(&(g_cfg->log), LOG_LEVEL_ERROR, "found null session " "descriptor!"); } else { g_sigterm(tmp->item->pid); } /* go on */ tmp=tmp->next; } /*THREAD-FIX release chain lock */ lock_chain_release(); } /******************************************************************************/ struct session_item* DEFAULT_CC session_get_bypid(int pid) { struct session_chain* tmp; struct session_item* dummy; dummy = g_malloc(sizeof(struct session_item), 1); if (0 == dummy) { log_message(&(g_cfg->log), LOG_LEVEL_ERROR, "internal error", pid); return 0; } /*THREAD-FIX require chain lock */ lock_chain_acquire(); tmp = g_sessions; while (tmp != 0) { if (tmp->item == 0) { log_message(&(g_cfg->log), LOG_LEVEL_ERROR, "session descriptor for " "pid %d is null!", pid); /*THREAD-FIX release chain lock */ lock_chain_release(); return 0; } if (tmp->item->pid == pid) { /*THREAD-FIX release chain lock */ g_memcpy(dummy, tmp->item, sizeof(struct session_item)); lock_chain_release(); /*return tmp->item;*/ return dummy; } /* go on */ tmp=tmp->next; } /*THREAD-FIX release chain lock */ lock_chain_release(); return 0; } /******************************************************************************/ struct SCP_DISCONNECTED_SESSION* session_get_byuser(char* user, int* cnt, unsigned char flags) { struct session_chain* tmp; struct SCP_DISCONNECTED_SESSION* sess; int count; int index; count=0; /*THREAD-FIX require chain lock */ lock_chain_acquire(); tmp = g_sessions; while (tmp != 0) { LOG_DBG(&(g_cfg->log), "user: %s", user); if ((NULL == user) || (!g_strncasecmp(user, tmp->item->name, 256))) { LOG_DBG(&(g_cfg->log), "session_get_byuser: status=%d, flags=%d, " "result=%d", (tmp->item->status), flags, ((tmp->item->status) & flags)); if ((tmp->item->status) & flags) { count++; } } /* go on */ tmp=tmp->next; } if (count==0) { (*cnt)=0; /*THREAD-FIX release chain lock */ lock_chain_release(); return 0; } /* malloc() an array of disconnected sessions */ sess=g_malloc(count * sizeof(struct SCP_DISCONNECTED_SESSION),1); if (sess==0) { (*cnt)=0; /*THREAD-FIX release chain lock */ lock_chain_release(); return 0; } tmp = g_sessions; index = 0; while (tmp != 0) { #warning FIXME: we should get only disconnected sessions! if ((NULL == user) || (!g_strncasecmp(user, tmp->item->name, 256))) { if ((tmp->item->status) & flags) { (sess[index]).SID=tmp->item->pid; (sess[index]).type=tmp->item->type; (sess[index]).height=tmp->item->height; (sess[index]).width=tmp->item->width; (sess[index]).bpp=tmp->item->bpp; #warning FIXME: setting idle times and such /*(sess[index]).connect_time.year = tmp->item->connect_time.year; (sess[index]).connect_time.month = tmp->item->connect_time.month; (sess[index]).connect_time.day = tmp->item->connect_time.day; (sess[index]).connect_time.hour = tmp->item->connect_time.hour; (sess[index]).connect_time.minute = tmp->item->connect_time.minute; (sess[index]).disconnect_time.year = tmp->item->disconnect_time.year; (sess[index]).disconnect_time.month = tmp->item->disconnect_time.month; (sess[index]).disconnect_time.day = tmp->item->disconnect_time.day; (sess[index]).disconnect_time.hour = tmp->item->disconnect_time.hour; (sess[index]).disconnect_time.minute = tmp->item->disconnect_time.minute; (sess[index]).idle_time.year = tmp->item->idle_time.year; (sess[index]).idle_time.month = tmp->item->idle_time.month; (sess[index]).idle_time.day = tmp->item->idle_time.day; (sess[index]).idle_time.hour = tmp->item->idle_time.hour; (sess[index]).idle_time.minute = tmp->item->idle_time.minute;*/ (sess[index]).conn_year = tmp->item->connect_time.year; (sess[index]).conn_month = tmp->item->connect_time.month; (sess[index]).conn_day = tmp->item->connect_time.day; (sess[index]).conn_hour = tmp->item->connect_time.hour; (sess[index]).conn_minute = tmp->item->connect_time.minute; (sess[index]).idle_days = tmp->item->idle_time.day; (sess[index]).idle_hours = tmp->item->idle_time.hour; (sess[index]).idle_minutes = tmp->item->idle_time.minute; index++; } } /* go on */ tmp=tmp->next; } /*THREAD-FIX release chain lock */ lock_chain_release(); (*cnt)=count; return sess; } xrdp-0.6.0/sesman/session.h000066400000000000000000000067031203155130500156150ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2005-2008 */ /** * * @file session.h * @brief Session management definitions * @author Jay Sorg, Simone Fedele * */ #ifndef SESSION_H #define SESSION_H #include "libscp_types.h" #define SESMAN_SESSION_TYPE_XRDP 1 #define SESMAN_SESSION_TYPE_XVNC 2 #define SESMAN_SESSION_STATUS_ACTIVE 0x01 #define SESMAN_SESSION_STATUS_IDLE 0x02 #define SESMAN_SESSION_STATUS_DISCONNECTED 0x04 /* future expansion #define SESMAN_SESSION_STATUS_REMCONTROL 0x08 */ #define SESMAN_SESSION_STATUS_ALL 0xFF #define SESMAN_SESSION_KILL_OK 0 #define SESMAN_SESSION_KILL_NULLITEM 1 #define SESMAN_SESSION_KILL_NOTFOUND 2 struct session_date { tui16 year; tui8 month; tui8 day; tui8 hour; tui8 minute; }; #define zero_time(s) { (s)->year=0; (s)->month=0; (s)->day=0; (s)->hour=0; (s)->minute=0; } struct session_item { char name[256]; int pid; /* pid of sesman waiting for wm to end */ int display; int width; int height; int bpp; long data; /* status info */ unsigned char status; unsigned char type; /* time data */ struct session_date connect_time; struct session_date disconnect_time; struct session_date idle_time; char client_ip[256]; }; struct session_chain { struct session_chain* next; struct session_item* item; }; /** * * @brief finds a session matching the supplied parameters * @return session data or 0 * */ struct session_item* DEFAULT_CC session_get_bydata(char* name, int width, int height, int bpp, int type); #ifndef session_find_item #define session_find_item(a, b, c, d, e) session_get_bydata(a, b, c, d, e); #endif /** * * @brief starts a session * @return 0 on error, display number if success * */ int DEFAULT_CC session_start(int width, int height, int bpp, char* username, char* password, long data, tui8 type, char* domain, char* program, char* directory, char* client_ip); /** * * @brief starts a session * @return error * */ int APP_CC session_sync_start(void); /** * * @brief kills a session * @param pid the pid of the session to be killed * @return * */ int DEFAULT_CC session_kill(int pid); /** * * @brief sends sigkill to all sessions * @return * */ void DEFAULT_CC session_sigkill_all(); /** * * @brief retrieves a session's descriptor * @param pid the session pid * @return a pointer to the session descriptor on success, NULL otherwise * */ struct session_item* DEFAULT_CC session_get_bypid(int pid); /** * * @brief retrieves a session's descriptor * @param pid the session pid * @return a pointer to the session descriptor on success, NULL otherwise * */ struct SCP_DISCONNECTED_SESSION* session_get_byuser(char* user, int* cnt, unsigned char flags); #endif xrdp-0.6.0/sesman/sessvc/000077500000000000000000000000001203155130500152615ustar00rootroot00000000000000xrdp-0.6.0/sesman/sessvc/Makefile.am000066400000000000000000000005321203155130500173150ustar00rootroot00000000000000 AM_CFLAGS = \ -DXRDP_CFG_PATH=\"${sysconfdir}/xrdp\" \ -DXRDP_SBIN_PATH=\"${sbindir}\" \ -DXRDP_SHARE_PATH=\"${datadir}/xrdp\" \ -DXRDP_PID_PATH=\"${localstatedir}/run\" INCLUDES = \ -I$(top_srcdir)/common sbin_PROGRAMS = \ xrdp-sessvc xrdp_sessvc_SOURCES = \ sessvc.c xrdp_sessvc_LDADD = \ $(top_srcdir)/common/libcommon.la xrdp-0.6.0/sesman/sessvc/sessvc.c000066400000000000000000000077251203155130500167460ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2005-2010 */ /** * * @file sessvc.c * @brief Session supervisor * @author Simone Fedele * */ #if defined(HAVE_CONFIG_H) #include "config_ac.h" #endif #include "file_loc.h" #include "os_calls.h" #include "arch.h" static int g_term = 0; /*****************************************************************************/ void DEFAULT_CC term_signal_handler(int sig) { g_writeln("xrdp-sessvc: term_signal_handler: got signal %d", sig); g_term = 1; } /*****************************************************************************/ void DEFAULT_CC nil_signal_handler(int sig) { g_writeln("xrdp-sessvc: nil_signal_handler: got signal %d", sig); } /******************************************************************************/ /* chansrv can exit at any time without cleaning up, its an xlib app */ int APP_CC chansrv_cleanup(int pid) { char text[256]; g_snprintf(text, 255, "/tmp/.xrdp/xrdp_chansrv_%8.8x_main_term", pid); if (g_file_exist(text)) { g_file_delete(text); } g_snprintf(text, 255, "/tmp/.xrdp/xrdp_chansrv_%8.8x_thread_done", pid); if (g_file_exist(text)) { g_file_delete(text); } return 0; } /******************************************************************************/ int DEFAULT_CC main(int argc, char** argv) { int ret = 0; int chansrv_pid = 0; int wm_pid = 0; int x_pid = 0; int lerror = 0; char exe_path[262]; g_init("xrdp-sessvc"); g_memset(exe_path,0,sizeof(exe_path)); if (argc < 3) { g_writeln("xrdp-sessvc: exiting, not enough parameters"); g_deinit(); return 1; } g_signal_kill(term_signal_handler); /* SIGKILL */ g_signal_terminate(term_signal_handler); /* SIGTERM */ g_signal_user_interrupt(term_signal_handler); /* SIGINT */ g_signal_pipe(nil_signal_handler); /* SIGPIPE */ x_pid = g_atoi(argv[1]); wm_pid = g_atoi(argv[2]); g_writeln("xrdp-sessvc: waiting for X (pid %d) and WM (pid %d)", x_pid, wm_pid); /* run xrdp-chansrv as a seperate process */ chansrv_pid = g_fork(); if (chansrv_pid == -1) { g_writeln("xrdp-sessvc: fork error"); g_deinit(); return 1; } else if (chansrv_pid == 0) /* child */ { g_set_current_dir(XRDP_SBIN_PATH); g_snprintf(exe_path, 261, "%s/xrdp-chansrv", XRDP_SBIN_PATH); g_execlp3(exe_path, "xrdp-chansrv", 0); /* should not get here */ g_writeln("xrdp-sessvc: g_execlp3() failed"); g_deinit(); return 1; } lerror = 0; /* wait for window manager to get done */ ret = g_waitpid(wm_pid); while ((ret == 0) && !g_term) { ret = g_waitpid(wm_pid); g_sleep(1); } if (ret < 0) { lerror = g_get_errno(); } g_writeln("xrdp-sessvc: WM is dead (waitpid said %d, errno is %d) " "exiting...", ret, lerror); /* kill channel server */ g_writeln("xrdp-sessvc: stopping channel server"); g_sigterm(chansrv_pid); ret = g_waitpid(chansrv_pid); while ((ret == 0) && !g_term) { ret = g_waitpid(chansrv_pid); g_sleep(1); } chansrv_cleanup(chansrv_pid); /* kill X server */ g_writeln("xrdp-sessvc: stopping X server"); g_sigterm(x_pid); ret = g_waitpid(x_pid); while ((ret == 0) && !g_term) { ret = g_waitpid(x_pid); g_sleep(1); } g_writeln("xrdp-sessvc: clean exit"); g_deinit(); return 0; } xrdp-0.6.0/sesman/sig.c000066400000000000000000000117121203155130500147030ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2005-2010 */ /** * * @file sig.c * @brief signal handling functions * @author Jay Sorg, Simone Fedele * */ #include "sesman.h" #include "signal.h" extern int g_sck; extern int g_pid; extern struct config_sesman* g_cfg; /* in sesman.c */ extern tbus g_term_event; /******************************************************************************/ void DEFAULT_CC sig_sesman_shutdown(int sig) { char pid_file[256]; log_message(&(g_cfg->log), LOG_LEVEL_INFO, "shutting down sesman %d", 1); if (g_getpid() != g_pid) { LOG_DBG(&(g_cfg->log), "g_getpid() [%d] differs from g_pid [%d]", (g_getpid()), g_pid); return; } LOG_DBG(&(g_cfg->log), " - getting signal %d pid %d", sig, g_getpid()); g_set_wait_obj(g_term_event); g_tcp_close(g_sck); session_sigkill_all(); g_snprintf(pid_file, 255, "%s/xrdp-sesman.pid", XRDP_PID_PATH); g_file_delete(pid_file); } /******************************************************************************/ void DEFAULT_CC sig_sesman_reload_cfg(int sig) { int error; struct config_sesman *cfg; log_message(&(g_cfg->log), LOG_LEVEL_WARNING, "receiving SIGHUP %d", 1); if (g_getpid() != g_pid) { LOG_DBG(&(g_cfg->log), "g_getpid() [%d] differs from g_pid [%d]", g_getpid(), g_pid); return; } cfg = g_malloc(sizeof(struct config_sesman), 1); if (0 == cfg) { log_message(&(g_cfg->log), LOG_LEVEL_ERROR, "error creating new config: - keeping old cfg"); return; } if (config_read(cfg) != 0) { log_message(&(g_cfg->log), LOG_LEVEL_ERROR, "error reading config - keeping old cfg"); return; } /* stop logging subsystem */ log_end(&(g_cfg->log)); /* replace old config with new readed one */ g_cfg = cfg; /* start again logging subsystem */ error = log_start(&(g_cfg->log)); if (error != LOG_STARTUP_OK) { switch (error) { case LOG_ERROR_MALLOC: g_printf("error on malloc. cannot restart logging. log stops here, sorry.\n"); break; case LOG_ERROR_FILE_OPEN: g_printf("error reopening log file [%s]. log stops here, sorry.\n", g_cfg->log.log_file); break; } } log_message(&(g_cfg->log), LOG_LEVEL_INFO, "configuration reloaded, log subsystem restarted"); } /******************************************************************************/ void DEFAULT_CC sig_sesman_session_end(int sig) { int pid; if (g_getpid() != g_pid) { return; } pid = g_waitchild(); if (pid > 0) { session_kill(pid); } } /******************************************************************************/ void* DEFAULT_CC sig_handler_thread(void* arg) { int recv_signal; sigset_t sigmask; sigset_t oldmask; sigset_t waitmask; /* mask signals to be able to wait for them... */ sigfillset(&sigmask); /* it is a good idea not to block SIGILL SIGSEGV */ /* SIGFPE -- see sigaction(2) NOTES */ pthread_sigmask(SIG_BLOCK, &sigmask, &oldmask); /* building the signal wait mask... */ sigemptyset(&waitmask); sigaddset(&waitmask, SIGHUP); sigaddset(&waitmask, SIGCHLD); sigaddset(&waitmask, SIGTERM); sigaddset(&waitmask, SIGKILL); sigaddset(&waitmask, SIGINT); // sigaddset(&waitmask, SIGFPE); // sigaddset(&waitmask, SIGILL); // sigaddset(&waitmask, SIGSEGV); do { LOG_DBG(&(g_cfg->log), "calling sigwait()",0); sigwait(&waitmask, &recv_signal); switch (recv_signal) { case SIGHUP: //reload cfg //we must stop & restart logging, or copy logging cfg!!!! LOG_DBG(&(g_cfg->log), "sesman received SIGHUP", 0); //return 0; break; case SIGCHLD: /* a session died */ LOG_DBG(&(g_cfg->log), "sesman received SIGCHLD", 0); sig_sesman_session_end(SIGCHLD); break; case SIGINT: /* we die */ LOG_DBG(&(g_cfg->log), "sesman received SIGINT", 0); sig_sesman_shutdown(recv_signal); break; case SIGKILL: /* we die */ LOG_DBG(&(g_cfg->log), "sesman received SIGKILL", 0); sig_sesman_shutdown(recv_signal); break; case SIGTERM: /* we die */ LOG_DBG(&(g_cfg->log), "sesman received SIGTERM", 0); sig_sesman_shutdown(recv_signal); break; } } while (1); return 0; } xrdp-0.6.0/sesman/sig.h000066400000000000000000000026021203155130500147060ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2005-2010 */ /** * * @file sig.h * @brief Signal handling function declarations * @author Jay Sorg, Simone Fedele * */ #ifndef SIG_H #define SIG_H /** * * @brief Shutdown signal code * @param sig The received signal * */ void DEFAULT_CC sig_sesman_shutdown(int sig); /** * * @brief SIGHUP handling code * @param sig The received signal * */ void DEFAULT_CC sig_sesman_reload_cfg(int sig); /** * * @brief SIGCHLD handling code * @param sig The received signal * */ void DEFAULT_CC sig_sesman_session_end(int sig); /** * * @brief signal handling thread * */ void* DEFAULT_CC sig_handler_thread(void* arg); #endif xrdp-0.6.0/sesman/startwm.sh000077500000000000000000000033761203155130500160240ustar00rootroot00000000000000#!/bin/sh # change the order in line below to run to run whatever window manager you # want, default to kde SESSIONS="gnome-session blackbox fluxbox startxfce4 startkde xterm" #start the window manager wm_start() { for WindowManager in $SESSIONS do which $WindowManager if test $? -eq 0 then echo "Starting $WindowManager" $WindowManager return 0 fi done return 0 } #Execution sequence for interactive login shell #Following pseudo code explains the sequence of execution of these files. #execute /etc/profile #IF ~/.bash_profile exists THEN # execute ~/.bash_profile #ELSE # IF ~/.bash_login exist THEN # execute ~/.bash_login # ELSE # IF ~/.profile exist THEN # execute ~/.profile # END IF # END IF #END IF pre_start() { if [ -f /etc/profile ] then . /etc/profile fi if [ -f ~/.bash_profile ] then . ~/.bash_profile else if [ -f ~/.bash_login ] then . ~/.bash_login else if [ -f ~/.profile ] then . ~/.profile fi fi fi return 0 } #When you logout of the interactive shell, following is the #sequence of execution: #IF ~/.bash_logout exists THEN # execute ~/.bash_logout #END IF post_start() { if [ -f ~/.bash_logout ] then . ~/.bash_logout fi return 0 } #. /etc/environment #export PATH=$PATH #export LANG=$LANG # change PATH to be what your environment needs usually what is in # /etc/environment #PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games" #export PATH=$PATH # for PATH and LANG from /etc/environment # pam will auto process the environment file if /etc/pam.d/xrdp-sesman # includes # auth required pam_env.so readenv=1 pre_start wm_start post_start exit 1 xrdp-0.6.0/sesman/thread.c000066400000000000000000000124561203155130500153760ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2005-2010 */ /** * * @file thread.c * @brief thread stuff... * @author Simone Fedele * */ #include "sesman.h" #include #include #include extern struct config_sesman* g_cfg; /* in sesman.c */ static pthread_t g_thread_sighandler; //static pthread_t g_thread_updater; /* a variable to pass the socket of s connection to a thread */ int g_thread_sck; /******************************************************************************/ int DEFAULT_CC thread_sighandler_start(void) { int ret; sigset_t sigmask; sigset_t oldmask; sigset_t waitmask; /* mask signals to be able to wait for them... */ sigfillset(&sigmask); pthread_sigmask(SIG_BLOCK, &sigmask, &oldmask); /* unblock some signals... */ sigemptyset(&waitmask); /* it is a good idea not to block SIGILL SIGSEGV */ /* SIGFPE -- see sigaction(2) NOTES */ sigaddset(&waitmask, SIGILL); sigaddset(&waitmask, SIGSEGV); sigaddset(&waitmask, SIGFPE); pthread_sigmask(SIG_UNBLOCK, &waitmask, NULL); log_message(&(g_cfg->log), LOG_LEVEL_INFO,"starting signal handling thread..."); ret = pthread_create(&g_thread_sighandler, NULL, sig_handler_thread, ""); pthread_detach(g_thread_sighandler); if (ret == 0) { log_message(&(g_cfg->log), LOG_LEVEL_INFO, "signal handler thread started successfully"); return 0; } /* if something happened while starting a new thread... */ switch (ret) { case EINVAL: log_message(&(g_cfg->log), LOG_LEVEL_ERROR, "invalid attributes for signal handling thread (creation returned EINVAL)"); break; case EAGAIN: log_message(&(g_cfg->log), LOG_LEVEL_ERROR, "not enough resources to start signal handling thread (creation returned EAGAIN)"); break; case EPERM: log_message(&(g_cfg->log), LOG_LEVEL_ERROR, "invalid permissions for signal handling thread (creation returned EPERM)"); break; default: log_message(&(g_cfg->log), LOG_LEVEL_ERROR, "unknown error starting signal handling thread"); } return 1; } #ifdef JUST_TO_AVOID_COMPILER_ERRORS /******************************************************************************/ int DEFAULT_CC thread_session_update_start(void) { int ret; //starts the session update thread //that checks for idle time, destroys sessions, ecc... #warning this thread should always request lock_fork before read or write #warning (so we can Fork() In Peace) ret = pthread_create(&g_thread_updater, NULL, , ""); pthread_detach(g_thread_updater); if (ret==0) { log_message(&(g_cfg->log), LOG_LEVEL_INFO, "session update thread started successfully"); return 0; } /* if something happened while starting a new thread... */ switch (ret) { case EINVAL: log_message(&(g_cfg->log), LOG_LEVEL_ERROR, "invalid attributes for session update thread (creation returned EINVAL)"); break; case EAGAIN: log_message(&(g_cfg->log), LOG_LEVEL_ERROR, "not enough resources to start session update thread (creation returned EAGAIN)"); break; case EPERM: log_message(&(g_cfg->log), LOG_LEVEL_ERROR, "invalid permissions for session update thread (creation returned EPERM)"); break; default: log_message(&(g_cfg->log), LOG_LEVEL_ERROR, "unknown error starting session update thread"); } return 1; } #endif /******************************************************************************/ int DEFAULT_CC thread_scp_start(int skt) { int ret; pthread_t th; /* blocking the use of thread_skt */ lock_socket_acquire(); g_thread_sck = skt; /* start a thread that processes a connection */ ret = pthread_create(&th, NULL, scp_process_start, ""); //ret = pthread_create(&th, NULL, scp_process_start, (void*) (&g_thread_sck)); pthread_detach(th); if (ret == 0) { log_message(&(g_cfg->log), LOG_LEVEL_INFO, "scp thread on sck %d started successfully", skt); return 0; } /* if something happened while starting a new thread... */ switch (ret) { case EINVAL: log_message(&(g_cfg->log), LOG_LEVEL_ERROR, "invalid attributes for scp thread on sck %d (creation returned EINVAL)", skt); break; case EAGAIN: log_message(&(g_cfg->log), LOG_LEVEL_ERROR, "not enough resources to start scp thread on sck %d (creation returned EAGAIN)", skt); break; case EPERM: log_message(&(g_cfg->log), LOG_LEVEL_ERROR, "invalid permissions for scp thread on sck %d (creation returned EPERM)", skt); break; default: log_message(&(g_cfg->log), LOG_LEVEL_ERROR, "unknown error starting scp thread on sck %d"); } return 1; } xrdp-0.6.0/sesman/thread.h000066400000000000000000000024011203155130500153700ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2005-2010 */ /** * * @file thread.h * @brief thread stuff... * @author Simone Fedele * */ #ifndef THREAD_H #define THREAD_H /** * * @brief Starts the signal handling thread * @retval 0 on success * @retval 1 on error * */ int DEFAULT_CC thread_sighandler_start(void); /** * * @brief Starts the session update thread * */ int DEFAULT_CC thread_session_update_start(void); /** * * @brief Starts a thread to handle an incoming connection * */ int DEFAULT_CC thread_scp_start(int skt); #endif xrdp-0.6.0/sesman/tools/000077500000000000000000000000001203155130500151135ustar00rootroot00000000000000xrdp-0.6.0/sesman/tools/Makefile.am000066400000000000000000000014521203155130500171510ustar00rootroot00000000000000EXTRA_DIST = tcp.h AM_CFLAGS = \ -DXRDP_CFG_PATH=\"${sysconfdir}/xrdp\" \ -DXRDP_SBIN_PATH=\"${sbindir}\" \ -DXRDP_SHARE_PATH=\"${datadir}/xrdp\" \ -DXRDP_PID_PATH=\"${localstatedir}/run\" INCLUDES = \ -I$(top_srcdir)/common \ -I$(top_srcdir)/sesman/libscp \ -I$(top_srcdir)/sesman bin_PROGRAMS = \ xrdp-sesrun \ xrdp-sestest \ xrdp-sesadmin \ xrdp-dis xrdp_sesrun_SOURCES = \ sesrun.c \ tcp.c \ config.c xrdp_sestest_SOURCES = \ sestest.c xrdp_sesadmin_SOURCES = \ sesadmin.c xrdp_dis_SOURCES = \ dis.c xrdp_sesrun_LDADD = \ $(top_srcdir)/common/libcommon.la xrdp_sestest_LDADD = \ $(top_srcdir)/common/libcommon.la \ $(top_srcdir)/sesman/libscp/libscp.la xrdp_sesadmin_LDADD = \ $(top_srcdir)/common/libcommon.la \ $(top_srcdir)/sesman/libscp/libscp.la xrdp-0.6.0/sesman/tools/dis.c000066400000000000000000000032741203155130500160440ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2011 */ #include #include #include #include #include #include int main(int argc, char** argv) { int sck; int dis; struct sockaddr_un sa; size_t len; char* p; char* display; if (argc != 1) { printf("xrdp disconnect utility\n"); printf("run with no parameters to disconnect you xrdp session\n"); return 0; } display = getenv("DISPLAY"); if (display == 0) { printf("display not set\n"); return 1; } dis = strtol(display + 1, &p, 10); memset(&sa, 0, sizeof(sa)); sa.sun_family = AF_UNIX; sprintf(sa.sun_path, "/tmp/.xrdp/xrdp_disconnect_display_%d", dis); if (access(sa.sun_path, F_OK) != 0) { printf("not in an xrdp session\n"); return 1; } sck = socket(PF_UNIX, SOCK_DGRAM, 0); len = sizeof(sa); if (sendto(sck, "sig", 4, 0, (struct sockaddr*)&sa, len) > 0) { printf("message sent ok\n"); } return 0; } xrdp-0.6.0/sesman/tools/sesadmin.c000066400000000000000000000105171203155130500170660ustar00rootroot00000000000000/* * sesadmin.c - an sesman administration tool * (c) 2008 Simone Fedele * */ #include "arch.h" #include "tcp.h" #include "libscp.h" #include "parse.h" #include "log.h" #include "libscp.h" #include #include char user[257]; char pass[257]; char cmnd[257]; char serv[257]; char port[257]; struct log_config logging; void cmndList(struct SCP_CONNECTION* c); void cmndKill(struct SCP_CONNECTION* c, struct SCP_SESSION* s); void cmndHelp(); int inputSession(struct SCP_SESSION* s); unsigned int menuSelect(unsigned int choices); int main(int argc, char** argv) { struct SCP_SESSION* s; struct SCP_CONNECTION* c; enum SCP_CLIENT_STATES_E e; //int end; int idx; //int sel; int sock; char* pwd; user[0]='\0'; pass[0]='\0'; cmnd[0]='\0'; serv[0]='\0'; port[0]='\0'; logging.program_name = g_strdup("sesadmin"); logging.log_file = g_strdup("xrdp-sesadmin.log"); logging.log_level = LOG_LEVEL_DEBUG; logging.enable_syslog = 0; log_start(&logging); for (idx = 0; idx < argc; idx++) { if (0 == g_strncmp(argv[idx], "-u=", 3)) { g_strncpy(user, (argv[idx])+3, 256); } else if (0 == g_strncmp(argv[idx], "-p=", 3)) { g_strncpy(pass, (argv[idx])+3, 256); } else if (0 == g_strncmp(argv[idx], "-s=", 3)) { g_strncpy(serv, (argv[idx])+3, 256); } else if (0 == g_strncmp(argv[idx], "-i=", 3)) { g_strncpy(port, (argv[idx])+3, 256); } else if (0 == g_strncmp(argv[idx], "-c=", 3)) { g_strncpy(cmnd, (argv[idx])+3, 256); } } if (0 == g_strncmp(serv, "", 1)) { g_strncpy(serv, "localhost", 256); } if (0 == g_strncmp(port, "", 1)) { g_strncpy(port, "3350", 256); } if (0 == g_strncmp(user, "", 1)) { g_strncpy(user, "root", 256); } if (0 == g_strncmp(pass, "", 1)) { pwd = getpass("password:"); g_strncpy(pass, pwd, 256); /* zeroing the password */ while ((*pwd) != '\0') { (*pwd) = 0x00; pwd++; } } scp_init(&logging); sock = g_tcp_socket(); s = scp_session_create(); c = scp_connection_create(sock); LOG_DBG(&logging, "Connecting to %s:%s with user %s (%s)\n", serv, port, user, pass); if (0 != g_tcp_connect(sock, serv, port)) { LOG_DBG(&logging, "g_tcp_connect() error\n"); return 1; } scp_session_set_type(s, SCP_SESSION_TYPE_MANAGE); scp_session_set_version(s, 1); scp_session_set_username(s, user); scp_session_set_password(s, pass); e = scp_v1c_mng_connect(c,s); if (SCP_CLIENT_STATE_OK != e) { LOG_DBG(&logging, "libscp error connecting: %s %d\n", s->errstr, (int)e); } if (0 == g_strncmp(cmnd, "list", 5)) { cmndList(c); } else if (0 == g_strncmp(cmnd, "kill:", 5)) { cmndKill(c,s); } g_tcp_close(sock); scp_session_destroy(s); scp_connection_destroy(c); log_end(&logging); return 0; } void cmndHelp() { fprintf(stderr, "sesadmin - a console sesman adminitration tool\n"); fprintf(stderr, "sysntax: sesadmin [] COMMAND [OPTIONS]\n\n"); fprintf(stderr, "-u=: username to connect to sesman [MANDATORY]\n"); fprintf(stderr, "-p=: password to connect to sesman [MANDATORY]\n"); fprintf(stderr, "-s=: sesman host (default is localhost)\n"); fprintf(stderr, "-i= : sesman port (default 3350)\n"); fprintf(stderr, "-c= : command to execute on the server [MANDATORY]\n"); fprintf(stderr, " it can be one of those:\n"); fprintf(stderr, " LIST\n"); fprintf(stderr, " KILL:\n"); } void cmndList(struct SCP_CONNECTION* c) { struct SCP_DISCONNECTED_SESSION* dsl; enum SCP_CLIENT_STATES_E e; int scnt; int idx; e = scp_v1c_mng_get_session_list(c, &scnt, &dsl); if ((SCP_CLIENT_STATE_LIST_OK == e) && (scnt > 0)) { for (idx = 0; idx < scnt; idx++) { printf("%d\t%d\t%dx%dx%d\t%d-%d-%d\t%04d/%02d/%02d@%02d:%02d\n", \ (dsl[idx]).SID, (dsl[idx]).type, (dsl[idx]).width, (dsl[idx]).height, (dsl[idx]).bpp, \ (dsl[idx]).idle_days, (dsl[idx]).idle_hours, (dsl[idx]).idle_minutes, \ (dsl[idx]).conn_year, (dsl[idx]).conn_month, (dsl[idx]).conn_day, (dsl[idx]).conn_hour, (dsl[idx]).conn_minute); } if (0 != dsl) { g_free(dsl); } } else { printf("No sessions.\n"); } } void cmndKill(struct SCP_CONNECTION* c, struct SCP_SESSION* s) { } xrdp-0.6.0/sesman/tools/sesrun.c000066400000000000000000000063651203155130500166100ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2005-2010 */ /** * * @file sesrun.c * @brief An utility to start a session * @author Jay Sorg, Simone Fedele * */ #include "sesman.h" #include "tcp.h" int g_sck; int g_pid; struct config_sesman g_cfg; /* config.h */ /******************************************************************************/ int DEFAULT_CC main(int argc, char** argv) { int sck; int code; int i; int size; int version; int width; int height; int bpp; int display; struct stream* in_s; struct stream* out_s; char* username; char* password; long data; if (0 != config_read(&g_cfg)) { g_printf("sesrun: error reading config. quitting.\n"); return 1; } g_pid = g_getpid(); if (argc == 1) { g_printf("xrdp session starter v0.1\n"); g_printf("\nusage:\n"); g_printf("sesrun \n"); } else if (argc == 7) { username = argv[2]; password = argv[3]; width = g_atoi(argv[4]); height = g_atoi(argv[5]); bpp = g_atoi(argv[6]); make_stream(in_s); init_stream(in_s, 8192); make_stream(out_s); init_stream(out_s, 8192); sck = g_tcp_socket(); if (g_tcp_connect(sck, argv[1], g_cfg.listen_port) == 0) { s_push_layer(out_s, channel_hdr, 8); out_uint16_be(out_s, 0); /* code */ i = g_strlen(username); out_uint16_be(out_s, i); out_uint8a(out_s, username, i); i = g_strlen(password); out_uint16_be(out_s, i); out_uint8a(out_s, password, i); out_uint16_be(out_s, width); out_uint16_be(out_s, height); out_uint16_be(out_s, bpp); s_mark_end(out_s); s_pop_layer(out_s, channel_hdr); out_uint32_be(out_s, 0); /* version */ out_uint32_be(out_s, out_s->end - out_s->data); /* size */ tcp_force_send(sck, out_s->data, out_s->end - out_s->data); if (tcp_force_recv(sck, in_s->data, 8) == 0) { in_uint32_be(in_s, version); in_uint32_be(in_s, size); init_stream(in_s, 8192); if (tcp_force_recv(sck, in_s->data, size - 8) == 0) { if (version == 0) { in_uint16_be(in_s, code); if (code == 3) { in_uint16_be(in_s, data); in_uint16_be(in_s, display); g_printf("ok %d display %d\n", data, display); } } } } } else { g_printf("connect error\n"); } g_tcp_close(sck); free_stream(in_s); free_stream(out_s); } return 0; } xrdp-0.6.0/sesman/tools/sestest.c000066400000000000000000000123461203155130500167570ustar00rootroot00000000000000/* * sestest.c - an scp_v1 testing tool * (c) 2008 Simone Fedele * */ #include "arch.h" #include "tcp.h" #include "libscp.h" #include "parse.h" #include "log.h" #include int inputSession(struct SCP_SESSION* s); unsigned int menuSelect(unsigned int choices); int main(int argc, char** argv) { char buf[256]; struct SCP_SESSION* s; struct SCP_CONNECTION* c; /*struct SCP_DISCONNECTED_SESSION ds;*/ struct SCP_DISCONNECTED_SESSION* dsl; enum SCP_CLIENT_STATES_E e; struct log_config log; int end; int scnt; int idx; int sel; int sock; log.enable_syslog=0; log.log_level=99; log.program_name=g_strdup("sestest"); log.log_file=g_strdup("sestest.log"); log_start(&log); scp_init(&log); sock=g_tcp_socket(); s = scp_session_create(); c = scp_connection_create(sock); if (0!=g_tcp_connect(sock, "localhost", "3350")) { g_printf("error connecting"); return 1; } g_printf("001 - send connect request\n"); scp_session_set_type(s, SCP_SESSION_TYPE_XVNC); scp_session_set_version(s, 1); scp_session_set_height(s, 600); scp_session_set_width(s, 800); scp_session_set_bpp(s, 16); scp_session_set_rsr(s, 0); scp_session_set_locale(s, "it_IT"); scp_session_set_username(s, "prog"); scp_session_set_password(s, "prog"); scp_session_set_hostname(s, "odin"); // scp_session_set_addr(s, SCP_ADDRESS_TYPE_IPV4, "127.0.0.1"); // scp_session_set_display(struct SCP_SESSION* s, SCP_DISPLAY display); // scp_session_set_errstr(struct SCP_SESSION* s, char* str); /*s.type=SCP_SESSION_TYPE_XVNC; s.version=1; s.height=600; s.width=800; s.bpp=8; s.rsr=0; g_strncpy(s.locale,"it_IT 0123456789",18); s.username=g_malloc(256, 1); g_strncpy(s.username,"prog",255); s.password=g_malloc(256,1); g_strncpy(s.password, "prog", 255); g_printf("%s - %s\n", s.username, s.password); s.hostname=g_malloc(256,1); g_strncpy(s.hostname, "odin", 255); s.addr_type=SCP_ADDRESS_TYPE_IPV4; s.ipv4addr=0; s.errstr=0;*/ end=0; e=scp_v1c_connect(c,s); while (!end) { switch (e) { case SCP_CLIENT_STATE_OK: g_printf("OK : display is %d\n", (short int)s->display); end=1; break; case SCP_CLIENT_STATE_SESSION_LIST: g_printf("OK : session list needed\n"); e=scp_v1c_get_session_list(c, &scnt, &dsl); break; case SCP_CLIENT_STATE_LIST_OK: g_printf("OK : selecting a session:\n"); for (idx=0; idx errstr); g_printf(" username:"); if (scanf("%255s", buf) < 0) { g_writeln("error"); } scp_session_set_username(s, buf); g_printf(" password:"); if (scanf("%255s", buf) < 0) { g_writeln("error"); } scp_session_set_password(s, buf); e=scp_v1c_resend_credentials(c,s); break; case SCP_CLIENT_STATE_CONNECTION_DENIED: g_printf("ERR: connection denied: %s\n", s->errstr); end=1; break; case SCP_CLIENT_STATE_PWD_CHANGE_REQ: g_printf("OK : password change required\n"); break; /*case SCP_CLIENT_STATE_RECONNECT_SINGLE: g_printf("OK : reconnect to 1 disconnected session\n"); e=scp_v1c_retrieve_session(&c, &s, &ds); g_printf("Session Type: %d on %d\n", ds.type, s.display); g_printf("Session Screen: %dx%dx%d\n", ds.height, ds.width, ds.bpp);*/ break; default: g_printf("protocol error: %d\n", e); end=1; } } g_tcp_close(sock); scp_session_destroy(s); scp_connection_destroy(c); /*free_stream(c.in_s); free_stream(c.out_s);*/ return 0; } int inputSession(struct SCP_SESSION* s) { unsigned int integer; g_printf("username: "); if (scanf("%255s", s->username) < 0) { g_writeln("error"); } g_printf("password:"); if (scanf("%255s", s->password) < 0) { g_writeln("error"); } g_printf("hostname:"); if (scanf("%255s", s->hostname) < 0) { g_writeln("error"); } g_printf("session type:\n"); g_printf("0: Xvnc\n", SCP_SESSION_TYPE_XVNC); g_printf("1: x11rdp\n", SCP_SESSION_TYPE_XRDP); integer=menuSelect(1); if (integer==1) { s->type=SCP_SESSION_TYPE_XRDP; } else { s->type=SCP_SESSION_TYPE_XVNC; } s->version=1; s->height=600; s->width=800; s->bpp=8; /* fixed for now */ s->rsr=0; g_strncpy(s->locale,"it_IT 0123456789",18); return 0; } tui32 menuSelect(tui32 choices) { tui32 sel; int ret; ret = scanf("%u", &sel); while ((ret==0) || (sel > choices)) { g_printf("invalid choice."); ret = scanf("%u", &sel); } return sel; } xrdp-0.6.0/sesman/tools/tcp.c000066400000000000000000000060061203155130500160470ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2005-2010 */ /** * * @file tcp.c * @brief Tcp stream funcions * @author Jay Sorg, Simone Fedele * */ #include "sesman.h" #include #include #include #include #include /*****************************************************************************/ int DEFAULT_CC tcp_force_recv(int sck, char* data, int len) { int rcvd; //#ifndef LIBSCP_CLIENT // int block; // block = lock_fork_critical_section_start(); //#endif while (len > 0) { rcvd = g_tcp_recv(sck, data, len, 0); if (rcvd == -1) { if (g_tcp_last_error_would_block(sck)) { g_sleep(1); } else { //#ifndef LIBSCP_CLIENT // lock_fork_critical_section_end(block); //#endif return 1; } } else if (rcvd == 0) { //#ifndef LIBSCP_CLIENT // lock_fork_critical_section_end(block); //#endif return 1; } else { data += rcvd; len -= rcvd; } } //#ifndef LIBSCP_CLIENT // lock_fork_critical_section_end(block); //#endif return 0; } /*****************************************************************************/ int DEFAULT_CC tcp_force_send(int sck, char* data, int len) { int sent; //#ifndef LIBSCP_CLIENT // int block; // block = lock_fork_critical_section_start(); //#endif while (len > 0) { sent = g_tcp_send(sck, data, len, 0); if (sent == -1) { if (g_tcp_last_error_would_block(sck)) { g_sleep(1); } else { //#ifndef LIBSCP_CLIENT // lock_fork_critical_section_end(block); //#endif return 1; } } else if (sent == 0) { //#ifndef LIBSCP_CLIENT // lock_fork_critical_section_end(block); //#endif return 1; } else { data += sent; len -= sent; } } //#ifndef LIBSCP_CLIENT // lock_fork_critical_section_end(block); //#endif return 0; } /*****************************************************************************/ int DEFAULT_CC tcp_bind(int sck, char* addr, char* port) { struct sockaddr_in s; memset(&s, 0, sizeof(struct sockaddr_in)); s.sin_family = AF_INET; s.sin_port = htons(atoi(port)); s.sin_addr.s_addr = inet_addr(addr); return bind(sck, (struct sockaddr*)&s, sizeof(struct sockaddr_in)); } xrdp-0.6.0/sesman/tools/tcp.h000066400000000000000000000032071203155130500160540ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2005-2010 */ /** * * @file tcp.h * @brief Tcp stream functions declarations * @author Jay Sorg, Simone Fedele * */ #ifndef TCP_H #define TCP_H /** * * @brief Force receiving data from tcp stream * @param sck The socket to read from * @param data Data buffer * @param len Data buffer size * @return 0 on success, 1 on error * */ int DEFAULT_CC tcp_force_recv(int sck, char* data, int len); /** * * @brief Force sending data to tcp stream * @param sck the socket to write to * @param data Data buffer * @param len Data buffer size * @return 0 on success, 1 on error * */ int DEFAULT_CC tcp_force_send(int sck, char* data, int len); /** * * @brief Binds the listening socket * @param sck Listening socket * @param addr Listening address * @param port Listening port * @return 0 on success, -1 on error * */ int DEFAULT_CC tcp_bind(int sck, char* addr, char* port); #endif xrdp-0.6.0/sesman/verify_user.c000066400000000000000000000150711203155130500164650ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2005-2008 */ /** * * @file verify_user.c * @brief Authenticate user using standard unix passwd/shadow system * @author Jay Sorg, Simone Fedele * */ #include "sesman.h" #define _XOPEN_SOURCE #include #include #include #include #include #ifndef SECS_PER_DAY #define SECS_PER_DAY (24L*3600L) #endif extern struct config_sesman* g_cfg; /* in sesman.c */ static int DEFAULT_CC auth_crypt_pwd(char* pwd, char* pln, char* crp); static int DEFAULT_CC auth_account_disabled(struct spwd* stp); /******************************************************************************/ /* returns boolean */ long DEFAULT_CC auth_userpass(char* user, char* pass) { char salt[13] = "$1$"; char hash[35] = ""; char* encr = 0; struct passwd* spw; struct spwd* stp; int saltcnt = 0; spw = getpwnam(user); if (spw == 0) { return 0; } if (g_strncmp(spw->pw_passwd, "x", 3) == 0) { /* the system is using shadow */ stp = getspnam(user); if (stp == 0) { return 0; } if (1==auth_account_disabled(stp)) { log_message(&(g_cfg->log), LOG_LEVEL_INFO, "account %s is disabled", user); return 0; } g_strncpy(hash, stp->sp_pwdp, 34); } else { /* old system with only passwd */ g_strncpy(hash, spw->pw_passwd, 34); } hash[34] = '\0'; if (g_strncmp(hash, "$1$", 3) == 0) { /* gnu style crypt(); */ saltcnt = 3; while ((hash[saltcnt] != '$') && (saltcnt < 11)) { salt[saltcnt] = hash[saltcnt]; saltcnt++; } salt[saltcnt] = '$'; salt[saltcnt + 1] = '\0'; } else { /* classic two char salt */ salt[0] = hash[0]; salt[1] = hash[1]; salt[2] = '\0'; } encr = crypt(pass,salt); if (g_strncmp(encr, hash, 34) != 0) { return 0; } return 1; } /******************************************************************************/ /* returns error */ int DEFAULT_CC auth_start_session(long in_val, int in_display) { return 0; } /******************************************************************************/ int DEFAULT_CC auth_end(long in_val) { return 0; } /******************************************************************************/ int DEFAULT_CC auth_set_env(long in_val) { return 0; } /******************************************************************************/ int DEFAULT_CC auth_check_pwd_chg(char* user) { struct passwd* spw; struct spwd* stp; int now; long today; spw = getpwnam(user); if (spw == 0) { return AUTH_PWD_CHG_ERROR; } if (g_strncmp(spw->pw_passwd, "x", 3) != 0) { /* old system with only passwd */ return AUTH_PWD_CHG_OK; } /* the system is using shadow */ stp = getspnam(user); if (stp == 0) { return AUTH_PWD_CHG_ERROR; } /* check if we need a pwd change */ now=g_time1(); today=now/SECS_PER_DAY; if (stp->sp_expire == -1) { return AUTH_PWD_CHG_OK; } if (today >= (stp->sp_lstchg + stp->sp_max - stp->sp_warn)) { return AUTH_PWD_CHG_CHANGE; } if (today >= (stp->sp_lstchg + stp->sp_max)) { return AUTH_PWD_CHG_CHANGE_MANDATORY; } if (today < ((stp->sp_lstchg)+(stp->sp_min))) { /* cannot change pwd for now */ return AUTH_PWD_CHG_NOT_NOW; } return AUTH_PWD_CHG_OK; } int DEFAULT_CC auth_change_pwd(char* user, char* newpwd) { struct passwd* spw; struct spwd* stp; char hash[35] = ""; long today; FILE* fd; if (0 != lckpwdf()) { return 1; } /* open passwd */ spw = getpwnam(user); if (spw == 0) { return 1; } if (g_strncmp(spw->pw_passwd, "x", 3) != 0) { /* old system with only passwd */ if (auth_crypt_pwd(spw->pw_passwd, newpwd, hash) != 0) { ulckpwdf(); return 1; } spw->pw_passwd=g_strdup(hash); fd = fopen("/etc/passwd", "rw"); putpwent(spw, fd); } else { /* the system is using shadow */ stp = getspnam(user); if (stp == 0) { return 1; } /* old system with only passwd */ if (auth_crypt_pwd(stp->sp_pwdp, newpwd, hash) != 0) { ulckpwdf(); return 1; } stp->sp_pwdp = g_strdup(hash); today = g_time1() / SECS_PER_DAY; stp->sp_lstchg = today; stp->sp_expire = today + stp->sp_max + stp->sp_inact; fd = fopen("/etc/shadow", "rw"); putspent(stp, fd); } ulckpwdf(); return 0; } /** * * @brief Password encryption * @param pwd Old password * @param pln Plaintext new password * @param crp Crypted new password * */ static int DEFAULT_CC auth_crypt_pwd(char* pwd, char* pln, char* crp) { char salt[13] = "$1$"; int saltcnt = 0; char* encr; if (g_strncmp(pwd, "$1$", 3) == 0) { /* gnu style crypt(); */ saltcnt = 3; while ((pwd[saltcnt] != '$') && (saltcnt < 11)) { salt[saltcnt] = pwd[saltcnt]; saltcnt++; } salt[saltcnt] = '$'; salt[saltcnt + 1] = '\0'; } else { /* classic two char salt */ salt[0] = pwd[0]; salt[1] = pwd[1]; salt[2] = '\0'; } encr = crypt(pln, salt); g_strncpy(crp, encr, 34); return 0; } /** * * @return 1 if the account is disabled, 0 otherwise * */ static int DEFAULT_CC auth_account_disabled(struct spwd* stp) { int today; if (0==stp) { /* if an invalid struct was passed we assume a disabled account */ return 1; } today=g_time1()/SECS_PER_DAY; LOG_DBG(&(g_cfg->log), "last %d",stp->sp_lstchg); LOG_DBG(&(g_cfg->log), "min %d",stp->sp_min); LOG_DBG(&(g_cfg->log), "max %d",stp->sp_max); LOG_DBG(&(g_cfg->log), "inact %d",stp->sp_inact); LOG_DBG(&(g_cfg->log), "warn %d",stp->sp_warn); LOG_DBG(&(g_cfg->log), "expire %d",stp->sp_expire); LOG_DBG(&(g_cfg->log), "today %d",today); if ((stp->sp_expire != -1) && (today >= stp->sp_expire)) { return 1; } if (today >= (stp->sp_lstchg+stp->sp_max+stp->sp_inact)) { return 1; } return 0; } xrdp-0.6.0/sesman/verify_user_kerberos.c000066400000000000000000000225471203155130500203670ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2005-2008 */ /** * * @file verify_user_kerberos.c * @brief Authenticate user using kerberos * @author Jay Sorg * */ #include "arch.h" #include "os_calls.h" #include typedef enum { INIT_PW, INIT_KT, RENEW, VALIDATE } action_type; struct k_opts { /* in seconds */ krb5_deltat starttime; krb5_deltat lifetime; krb5_deltat rlife; int forwardable; int proxiable; int addresses; int not_forwardable; int not_proxiable; int no_addresses; int verbose; char* principal_name; char* service_name; char* keytab_name; char* k5_cache_name; char* k4_cache_name; action_type action; }; struct k5_data { krb5_context ctx; krb5_ccache cc; krb5_principal me; char* name; }; struct user_info { char* name; char* pass; }; /******************************************************************************/ /* returns boolean */ static int DEFAULT_CC k5_begin(struct k_opts* opts, struct k5_data* k5, struct user_info* u_info) { krb5_error_code code = 0; code = krb5_init_context(&k5->ctx); if (code != 0) { g_printf("krb5_init_context failed in k5_begin\n"); return 0; } if (opts->k5_cache_name) { code = krb5_cc_resolve(k5->ctx, opts->k5_cache_name, &k5->cc); if (code != 0) { g_printf("krb5_cc_resolve failed in k5_begin\n"); return 0; } } else { code = krb5_cc_default(k5->ctx, &k5->cc); if (code != 0) { g_printf("krb5_cc_default failed in k5_begin\n"); return 0; } } if (opts->principal_name) { /* Use specified name */ code = krb5_parse_name(k5->ctx, opts->principal_name, &k5->me); if (code != 0) { g_printf("krb5_parse_name failed in k5_begin\n"); return 0; } } else { /* No principal name specified */ if (opts->action == INIT_KT) { /* Use the default host/service name */ code = krb5_sname_to_principal(k5->ctx, NULL, NULL, KRB5_NT_SRV_HST, &k5->me); if (code != 0) { g_printf("krb5_sname_to_principal failed in k5_begin\n"); return 0; } } else { /* Get default principal from cache if one exists */ code = krb5_cc_get_principal(k5->ctx, k5->cc, &k5->me); if (code != 0) { code = krb5_parse_name(k5->ctx, u_info->name, &k5->me); if (code != 0) { g_printf("krb5_parse_name failed in k5_begin\n"); return 0; } } } } code = krb5_unparse_name(k5->ctx, k5->me, &k5->name); if (code != 0) { g_printf("krb5_unparse_name failed in k5_begin\n"); return 0; } opts->principal_name = k5->name; return 1; } /******************************************************************************/ static void DEFAULT_CC k5_end(struct k5_data* k5) { if (k5->name) { krb5_free_unparsed_name(k5->ctx, k5->name); } if (k5->me) { krb5_free_principal(k5->ctx, k5->me); } if (k5->cc) { krb5_cc_close(k5->ctx, k5->cc); } if (k5->ctx) { krb5_free_context(k5->ctx); } g_memset(k5, 0, sizeof(struct k5_data)); } /******************************************************************************/ static krb5_error_code KRB5_CALLCONV kinit_prompter(krb5_context ctx, void* data, const char* name, const char* banner, int num_prompts, krb5_prompt prompts[]) { int i; krb5_prompt_type* types; krb5_error_code rc; struct user_info* u_info; u_info = (struct user_info*)data; rc = 0; types = krb5_get_prompt_types(ctx); for (i = 0; i < num_prompts; i++) { if (types[i] == KRB5_PROMPT_TYPE_PASSWORD || types[i] == KRB5_PROMPT_TYPE_NEW_PASSWORD_AGAIN) { g_strncpy(prompts[i].reply->data, u_info->pass, 255); } } return rc; } /******************************************************************************/ /* returns boolean */ static int k5_kinit(struct k_opts* opts, struct k5_data* k5, struct user_info* u_info) { char* doing; int notix = 1; krb5_keytab keytab = 0; krb5_creds my_creds; krb5_error_code code = 0; krb5_get_init_creds_opt options; krb5_address** addresses; krb5_get_init_creds_opt_init(&options); g_memset(&my_creds, 0, sizeof(my_creds)); /* From this point on, we can goto cleanup because my_creds is initialized. */ if (opts->lifetime) { krb5_get_init_creds_opt_set_tkt_life(&options, opts->lifetime); } if (opts->rlife) { krb5_get_init_creds_opt_set_renew_life(&options, opts->rlife); } if (opts->forwardable) { krb5_get_init_creds_opt_set_forwardable(&options, 1); } if (opts->not_forwardable) { krb5_get_init_creds_opt_set_forwardable(&options, 0); } if (opts->proxiable) { krb5_get_init_creds_opt_set_proxiable(&options, 1); } if (opts->not_proxiable) { krb5_get_init_creds_opt_set_proxiable(&options, 0); } if (opts->addresses) { addresses = NULL; code = krb5_os_localaddr(k5->ctx, &addresses); if (code != 0) { g_printf("krb5_os_localaddr failed in k5_kinit\n"); goto cleanup; } krb5_get_init_creds_opt_set_address_list(&options, addresses); } if (opts->no_addresses) { krb5_get_init_creds_opt_set_address_list(&options, NULL); } if ((opts->action == INIT_KT) && opts->keytab_name) { code = krb5_kt_resolve(k5->ctx, opts->keytab_name, &keytab); if (code != 0) { g_printf("krb5_kt_resolve failed in k5_kinit\n"); goto cleanup; } } switch (opts->action) { case INIT_PW: code = krb5_get_init_creds_password(k5->ctx, &my_creds, k5->me, 0, kinit_prompter, u_info, opts->starttime, opts->service_name, &options); break; case INIT_KT: code = krb5_get_init_creds_keytab(k5->ctx, &my_creds, k5->me, keytab, opts->starttime, opts->service_name, &options); break; case VALIDATE: code = krb5_get_validated_creds(k5->ctx, &my_creds, k5->me, k5->cc, opts->service_name); break; case RENEW: code = krb5_get_renewed_creds(k5->ctx, &my_creds, k5->me, k5->cc, opts->service_name); break; } if (code != 0) { doing = 0; switch (opts->action) { case INIT_PW: case INIT_KT: doing = "getting initial credentials"; break; case VALIDATE: doing = "validating credentials"; break; case RENEW: doing = "renewing credentials"; break; } if (code == KRB5KRB_AP_ERR_BAD_INTEGRITY) { g_printf("sesman: Password incorrect while %s in k5_kinit\n", doing); } else { g_printf("sesman: error while %s in k5_kinit\n", doing); } goto cleanup; } if (!opts->lifetime) { /* We need to figure out what lifetime to use for Kerberos 4. */ opts->lifetime = my_creds.times.endtime - my_creds.times.authtime; } code = krb5_cc_initialize(k5->ctx, k5->cc, k5->me); if (code != 0) { g_printf("krb5_cc_initialize failed in k5_kinit\n"); goto cleanup; } code = krb5_cc_store_cred(k5->ctx, k5->cc, &my_creds); if (code != 0) { g_printf("krb5_cc_store_cred failed in k5_kinit\n"); goto cleanup; } notix = 0; cleanup: if (my_creds.client == k5->me) { my_creds.client = 0; } krb5_free_cred_contents(k5->ctx, &my_creds); if (keytab) { krb5_kt_close(k5->ctx, keytab); } return notix ? 0 : 1; } /******************************************************************************/ /* returns boolean */ int DEFAULT_CC auth_userpass(char* user, char* pass) { struct k_opts opts; struct k5_data k5; struct user_info u_info; int got_k5; int authed_k5; g_memset(&opts, 0, sizeof(opts)); opts.action = INIT_PW; g_memset(&k5, 0, sizeof(k5)); g_memset(&u_info, 0, sizeof(u_info)); u_info.name = user; u_info.pass = pass; authed_k5 = 0; got_k5 = k5_begin(&opts, &k5, &u_info); if (got_k5) { authed_k5 = k5_kinit(&opts, &k5, &u_info); k5_end(&k5); } return authed_k5; } /******************************************************************************/ /* returns error */ int DEFAULT_CC auth_start_session(void) { return 0; } /******************************************************************************/ int DEFAULT_CC auth_end(void) { return 0; } /******************************************************************************/ int DEFAULT_CC auth_set_env(void) { return 0; } xrdp-0.6.0/sesman/verify_user_pam.c000066400000000000000000000140631203155130500173220ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2005-2008 */ /** * * @file verify_user_pam.c * @brief Authenticate user using pam * @author Jay Sorg * */ #include "arch.h" #include "os_calls.h" #include #include struct t_user_pass { char user[256]; char pass[256]; }; struct t_auth_info { struct t_user_pass user_pass; int session_opened; int did_setcred; struct pam_conv pamc; pam_handle_t* ph; }; /******************************************************************************/ static int DEFAULT_CC verify_pam_conv(int num_msg, const struct pam_message** msg, struct pam_response** resp, void* appdata_ptr) { int i; struct pam_response* reply; struct t_user_pass* user_pass; reply = g_malloc(sizeof(struct pam_response) * num_msg, 1); for (i = 0; i < num_msg; i++) { switch (msg[i]->msg_style) { case PAM_PROMPT_ECHO_ON: /* username */ user_pass = appdata_ptr; reply[i].resp = g_strdup(user_pass->user); reply[i].resp_retcode = PAM_SUCCESS; break; case PAM_PROMPT_ECHO_OFF: /* password */ user_pass = appdata_ptr; reply[i].resp = g_strdup(user_pass->pass); reply[i].resp_retcode = PAM_SUCCESS; break; default: g_printf("unknown in verify_pam_conv\r\n"); g_free(reply); return PAM_CONV_ERR; } } *resp = reply; return PAM_SUCCESS; } /******************************************************************************/ static void DEFAULT_CC get_service_name(char* service_name) { service_name[0] = 0; if (g_file_exist("/etc/pam.d/xrdp-sesman")) { g_strncpy(service_name, "xrdp-sesman", 255); } else { g_strncpy(service_name, "gdm", 255); } } /******************************************************************************/ /* returns long, zero is no go */ long DEFAULT_CC auth_userpass(char* user, char* pass) { int error; struct t_auth_info* auth_info; char service_name[256]; get_service_name(service_name); auth_info = g_malloc(sizeof(struct t_auth_info), 1); g_strncpy(auth_info->user_pass.user, user, 255); g_strncpy(auth_info->user_pass.pass, pass, 255); auth_info->pamc.conv = &verify_pam_conv; auth_info->pamc.appdata_ptr = &(auth_info->user_pass); error = pam_start(service_name, 0, &(auth_info->pamc), &(auth_info->ph)); if (error != PAM_SUCCESS) { g_printf("pam_start failed: %s\r\n", pam_strerror(auth_info->ph, error)); g_free(auth_info); return 0; } error = pam_authenticate(auth_info->ph, 0); if (error != PAM_SUCCESS) { g_printf("pam_authenticate failed: %s\r\n", pam_strerror(auth_info->ph, error)); g_free(auth_info); return 0; } error = pam_acct_mgmt(auth_info->ph, 0); if (error != PAM_SUCCESS) { g_printf("pam_acct_mgmt failed: %s\r\n", pam_strerror(auth_info->ph, error)); g_free(auth_info); return 0; } return (long)auth_info; } /******************************************************************************/ /* returns error */ int DEFAULT_CC auth_start_session(long in_val, int in_display) { struct t_auth_info* auth_info; int error; char display[256]; g_sprintf(display, ":%d", in_display); auth_info = (struct t_auth_info*)in_val; error = pam_set_item(auth_info->ph, PAM_TTY, display); if (error != PAM_SUCCESS) { g_printf("pam_set_item failed: %s\r\n", pam_strerror(auth_info->ph, error)); return 1; } error = pam_setcred(auth_info->ph, PAM_ESTABLISH_CRED); if (error != PAM_SUCCESS) { g_printf("pam_setcred failed: %s\r\n", pam_strerror(auth_info->ph, error)); return 1; } auth_info->did_setcred = 1; error = pam_open_session(auth_info->ph, 0); if (error != PAM_SUCCESS) { g_printf("pam_open_session failed: %s\r\n", pam_strerror(auth_info->ph, error)); return 1; } auth_info->session_opened = 1; return 0; } /******************************************************************************/ /* returns error */ /* cleanup */ int DEFAULT_CC auth_end(long in_val) { struct t_auth_info* auth_info; auth_info = (struct t_auth_info*)in_val; if (auth_info != 0) { if (auth_info->ph != 0) { if (auth_info->session_opened) { pam_close_session(auth_info->ph, 0); } if (auth_info->did_setcred) { pam_setcred(auth_info->ph, PAM_DELETE_CRED); } pam_end(auth_info->ph, PAM_SUCCESS); auth_info->ph = 0; } } g_free(auth_info); return 0; } /******************************************************************************/ /* returns error */ /* set any pam env vars */ int DEFAULT_CC auth_set_env(long in_val) { struct t_auth_info* auth_info; char** pam_envlist; char** pam_env; char item[256]; char value[256]; int eq_pos; auth_info = (struct t_auth_info*)in_val; if (auth_info != 0) { /* export PAM environment */ pam_envlist = pam_getenvlist(auth_info->ph); if (pam_envlist != NULL) { for (pam_env = pam_envlist; *pam_env != NULL; ++pam_env) { eq_pos = g_pos(*pam_env, "="); if (eq_pos >= 0 && eq_pos < 250) { g_strncpy(item, *pam_env, eq_pos); g_strncpy(value, (*pam_env) + eq_pos + 1, 255); g_setenv(item, value, 1); } g_free(*pam_env); } g_free(pam_envlist); } } return 0; } xrdp-0.6.0/sesman/verify_user_pam_userpass.c000066400000000000000000000044011203155130500212420ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2005-2008 */ /** * * @file verify_user_pam_userpass.c * @brief Authenticate user using pam_userpass module * @author Jay Sorg * */ #include "arch.h" #include "os_calls.h" #include #define SERVICE "xrdp" /******************************************************************************/ /* returns boolean */ int DEFAULT_CC auth_userpass(char* user, char* pass) { pam_handle_t* pamh; pam_userpass_t userpass; struct pam_conv conv = {pam_userpass_conv, &userpass}; const void* template1; int status; userpass.user = user; userpass.pass = pass; if (pam_start(SERVICE, user, &conv, &pamh) != PAM_SUCCESS) { return 0; } status = pam_authenticate(pamh, 0); if (status != PAM_SUCCESS) { pam_end(pamh, status); return 0; } status = pam_acct_mgmt(pamh, 0); if (status != PAM_SUCCESS) { pam_end(pamh, status); return 0; } status = pam_get_item(pamh, PAM_USER, &template1); if (status != PAM_SUCCESS) { pam_end(pamh, status); return 0; } if (pam_end(pamh, PAM_SUCCESS) != PAM_SUCCESS) { return 0; } return 1; } /******************************************************************************/ /* returns error */ int DEFAULT_CC auth_start_session(void) { return 0; } /******************************************************************************/ int DEFAULT_CC auth_end(void) { return 0; } /******************************************************************************/ int DEFAULT_CC auth_set_env(void) { return 0; } xrdp-0.6.0/vnc/000077500000000000000000000000001203155130500132535ustar00rootroot00000000000000xrdp-0.6.0/vnc/Makefile.am000066400000000000000000000005431203155130500153110ustar00rootroot00000000000000EXTRA_DIST = vnc.h AM_CFLAGS = \ -DXRDP_CFG_PATH=\"${sysconfdir}/xrdp\" \ -DXRDP_SBIN_PATH=\"${sbindir}\" \ -DXRDP_SHARE_PATH=\"${datadir}/xrdp\" \ -DXRDP_PID_PATH=\"${localstatedir}/run\" INCLUDES = \ -I$(top_srcdir)/common lib_LTLIBRARIES = \ libvnc.la libvnc_la_SOURCES = vnc.c libvnc_la_LIBADD = \ $(top_srcdir)/common/libcommon.la xrdp-0.6.0/vnc/vnc.c000066400000000000000000000730031203155130500142100ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2004-2010 libvnc */ #include "vnc.h" /******************************************************************************/ /* taken from vncauth.c */ void DEFAULT_CC rfbEncryptBytes(char* bytes, char* passwd) { char key[12]; /* key is simply password padded with nulls */ g_memset(key, 0, sizeof(key)); g_strncpy(key, passwd, 8); rfbDesKey((unsigned char*)key, EN0); /* 0, encrypt */ rfbDes((unsigned char*)bytes, (unsigned char*)bytes); rfbDes((unsigned char*)(bytes + 8), (unsigned char*)(bytes + 8)); } /******************************************************************************/ /* returns error */ int DEFAULT_CC lib_recv(struct vnc* v, char* data, int len) { int rcvd; if (v->sck_closed) { return 1; } while (len > 0) { rcvd = g_tcp_recv(v->sck, data, len, 0); if (rcvd == -1) { if (g_tcp_last_error_would_block(v->sck)) { if (v->server_is_term(v)) { return 1; } g_tcp_can_recv(v->sck, 10); } else { return 1; } } else if (rcvd == 0) { v->sck_closed = 1; return 1; } else { data += rcvd; len -= rcvd; } } return 0; } /*****************************************************************************/ /* returns error */ int DEFAULT_CC lib_send(struct vnc* v, char* data, int len) { int sent; if (v->sck_closed) { return 1; } while (len > 0) { sent = g_tcp_send(v->sck, data, len, 0); if (sent == -1) { if (g_tcp_last_error_would_block(v->sck)) { if (v->server_is_term(v)) { return 1; } g_tcp_can_send(v->sck, 10); } else { return 1; } } else if (sent == 0) { v->sck_closed = 1; return 1; } else { data += sent; len -= sent; } } return 0; } /******************************************************************************/ static int DEFAULT_CC lib_process_channel_data(struct vnc* v, int chanid, int flags, int size, struct stream* s, int total_size) { int type; int status; int length; int index; int format; struct stream* out_s; if (chanid == v->clip_chanid) { in_uint16_le(s, type); in_uint16_le(s, status); in_uint32_le(s, length); //g_writeln("clip data type %d status %d length %d", type, status, length); //g_hexdump(s->p, s->end - s->p); switch (type) { case 2: /* CLIPRDR_FORMAT_ANNOUNCE */ make_stream(out_s); init_stream(out_s, 8192); out_uint16_le(out_s, 3); out_uint16_le(out_s, 1); out_uint32_le(out_s, 0); out_uint8s(out_s, 4); /* pad */ s_mark_end(out_s); length = (int)(out_s->end - out_s->data); v->server_send_to_channel(v, v->clip_chanid, out_s->data, length, length, 3); free_stream(out_s); break; case 3: /* CLIPRDR_FORMAT_ACK */ break; case 4: /* CLIPRDR_DATA_REQUEST */ format = 0; if (length >= 4) { in_uint32_le(s, format); } /* only support CF_TEXT and CF_UNICODETEXT */ if ((format != 1) && (format != 13)) { break; } make_stream(out_s); init_stream(out_s, 8192); out_uint16_le(out_s, 5); out_uint16_le(out_s, 1); if (format == 13) /* CF_UNICODETEXT */ { out_uint32_le(out_s, v->clip_data_size * 2 + 2); for (index = 0; index < v->clip_data_size; index++) { out_uint8(out_s, v->clip_data[index]); out_uint8(out_s, 0); } out_uint8s(out_s, 2); } else if (format == 1) /* CF_TEXT */ { out_uint32_le(out_s, v->clip_data_size + 1); for (index = 0; index < v->clip_data_size; index++) { out_uint8(out_s, v->clip_data[index]); } out_uint8s(out_s, 1); } out_uint8s(out_s, 4); /* pad */ s_mark_end(out_s); length = (int)(out_s->end - out_s->data); v->server_send_to_channel(v, v->clip_chanid, out_s->data, length, length, 3); free_stream(out_s); break; } } else { g_writeln("lib_process_channel_data: unknown chanid %d v->clip_chanid %d", chanid, v->clip_chanid); } return 0; } /******************************************************************************/ int DEFAULT_CC lib_mod_event(struct vnc* v, int msg, long param1, long param2, long param3, long param4) { struct stream* s; int key; int error; int x; int y; int cx; int cy; int size; int total_size; int chanid; int flags; char* data; char text[256]; error = 0; make_stream(s); if (msg == 0x5555) /* channel data */ { chanid = LOWORD(param1); flags = HIWORD(param1); size = (int)param2; data = (char*)param3; total_size = (int)param4; if ((size >= 0) && (size <= (32 * 1024)) && (data != 0)) { init_stream(s, size); out_uint8a(s, data, size); s_mark_end(s); s->p = s->data; error = lib_process_channel_data(v, chanid, flags, size, s, total_size); } else { error = 1; } } else if ((msg >= 15) && (msg <= 16)) /* key events */ { key = param2; if (key > 0) { if (key == 65027) /* altgr */ { if (v->shift_state) { /* fix for mstsc sending left control down with altgr */ init_stream(s, 8192); out_uint8(s, 4); out_uint8(s, 0); /* down flag */ out_uint8s(s, 2); out_uint32_be(s, 65507); /* left control */ lib_send(v, s->data, 8); } } init_stream(s, 8192); out_uint8(s, 4); out_uint8(s, msg == 15); /* down flag */ out_uint8s(s, 2); out_uint32_be(s, key); error = lib_send(v, s->data, 8); if (key == 65507) /* left control */ { v->shift_state = msg == 15; } } } else if (msg >= 100 && msg <= 110) /* mouse events */ { switch (msg) { case 100: break; /* WM_MOUSEMOVE */ case 101: v->mod_mouse_state &= ~1; break; /* WM_LBUTTONUP */ case 102: v->mod_mouse_state |= 1; break; /* WM_LBUTTONDOWN */ case 103: v->mod_mouse_state &= ~4; break; /* WM_RBUTTONUP */ case 104: v->mod_mouse_state |= 4; break; /* WM_RBUTTONDOWN */ case 105: v->mod_mouse_state &= ~2; break; case 106: v->mod_mouse_state |= 2; break; case 107: v->mod_mouse_state &= ~8; break; case 108: v->mod_mouse_state |= 8; break; case 109: v->mod_mouse_state &= ~16; break; case 110: v->mod_mouse_state |= 16; break; } init_stream(s, 8192); out_uint8(s, 5); out_uint8(s, v->mod_mouse_state); out_uint16_be(s, param1); out_uint16_be(s, param2); error = lib_send(v, s->data, 6); } else if (msg == 200) /* invalidate */ { /* FrambufferUpdateRequest */ init_stream(s, 8192); out_uint8(s, 3); out_uint8(s, 0); x = (param1 >> 16) & 0xffff; out_uint16_be(s, x); y = param1 & 0xffff; out_uint16_be(s, y); cx = (param2 >> 16) & 0xffff; out_uint16_be(s, cx); cy = param2 & 0xffff; out_uint16_be(s, cy); error = lib_send(v, s->data, 10); } free_stream(s); return error; } //****************************************************************************** int DEFAULT_CC get_pixel_safe(char* data, int x, int y, int width, int height, int bpp) { int start = 0; int shift = 0; if (x < 0) { return 0; } if (y < 0) { return 0; } if (x >= width) { return 0; } if (y >= height) { return 0; } if (bpp == 1) { width = (width + 7) / 8; start = (y * width) + x / 8; shift = x % 8; return (data[start] & (0x80 >> shift)) != 0; } else if (bpp == 4) { width = (width + 1) / 2; start = y * width + x / 2; shift = x % 2; if (shift == 0) { return (data[start] & 0xf0) >> 4; } else { return data[start] & 0x0f; } } else if (bpp == 8) { return *(((unsigned char*)data) + (y * width + x)); } else if (bpp == 15 || bpp == 16) { return *(((unsigned short*)data) + (y * width + x)); } else if (bpp == 24 || bpp == 32) { return *(((unsigned int*)data) + (y * width + x)); } else { g_writeln("error in get_pixel_safe bpp %d", bpp); } return 0; } /******************************************************************************/ void DEFAULT_CC set_pixel_safe(char* data, int x, int y, int width, int height, int bpp, int pixel) { int start = 0; int shift = 0; if (x < 0) { return; } if (y < 0) { return; } if (x >= width) { return; } if (y >= height) { return; } if (bpp == 1) { width = (width + 7) / 8; start = (y * width) + x / 8; shift = x % 8; if (pixel & 1) { data[start] = data[start] | (0x80 >> shift); } else { data[start] = data[start] & ~(0x80 >> shift); } } else if (bpp == 15 || bpp == 16) { *(((unsigned short*)data) + (y * width + x)) = pixel; } else if (bpp == 24) { *(data + (3 * (y * width + x)) + 0) = pixel >> 0; *(data + (3 * (y * width + x)) + 1) = pixel >> 8; *(data + (3 * (y * width + x)) + 2) = pixel >> 16; } else { g_writeln("error in set_pixel_safe bpp %d", bpp); } } /******************************************************************************/ int DEFAULT_CC split_color(int pixel, int* r, int* g, int* b, int bpp, int* palette) { if (bpp == 8) { if (pixel >= 0 && pixel < 256 && palette != 0) { *r = (palette[pixel] >> 16) & 0xff; *g = (palette[pixel] >> 8) & 0xff; *b = (palette[pixel] >> 0) & 0xff; } } else if (bpp == 15) { *r = ((pixel >> 7) & 0xf8) | ((pixel >> 12) & 0x7); *g = ((pixel >> 2) & 0xf8) | ((pixel >> 8) & 0x7); *b = ((pixel << 3) & 0xf8) | ((pixel >> 2) & 0x7); } else if (bpp == 16) { *r = ((pixel >> 8) & 0xf8) | ((pixel >> 13) & 0x7); *g = ((pixel >> 3) & 0xfc) | ((pixel >> 9) & 0x3); *b = ((pixel << 3) & 0xf8) | ((pixel >> 2) & 0x7); } else if (bpp == 24 || bpp == 32) { *r = (pixel >> 16) & 0xff; *g = (pixel >> 8) & 0xff; *b = pixel & 0xff; } else { g_writeln("error in split_color bpp %d", bpp); } return 0; } /******************************************************************************/ int DEFAULT_CC make_color(int r, int g, int b, int bpp) { if (bpp == 24) { return (r << 16) | (g << 8) | b; } else { g_writeln("error in make_color bpp %d", bpp); } return 0; } /******************************************************************************/ int DEFAULT_CC lib_framebuffer_update(struct vnc* v) { char* data; char* d1; char* d2; char cursor_data[32 * (32 * 3)]; char cursor_mask[32 * (32 / 8)]; char text[256]; int num_recs; int i; int j; int k; int x; int y; int cx; int cy; int srcx; int srcy; int encoding; int Bpp; int pixel; int r; int g; int b; int data_size; int need_size; int error; struct stream* s; data_size = 0; data = 0; num_recs = 0; Bpp = (v->mod_bpp + 7) / 8; if (Bpp == 3) { Bpp = 4; } make_stream(s); init_stream(s, 8192); error = lib_recv(v, s->data, 3); if (error == 0) { in_uint8s(s, 1); in_uint16_be(s, num_recs); error = v->server_begin_update(v); } for (i = 0; i < num_recs; i++) { if (error != 0) { break; } init_stream(s, 8192); error = lib_recv(v, s->data, 12); if (error == 0) { in_uint16_be(s, x); in_uint16_be(s, y); in_uint16_be(s, cx); in_uint16_be(s, cy); in_uint32_be(s, encoding); if (encoding == 0) /* raw */ { need_size = cx * cy * Bpp; if (need_size > data_size) { g_free(data); data = (char*)g_malloc(need_size, 0); data_size = need_size; } error = lib_recv(v, data, need_size); if (error == 0) { error = v->server_paint_rect(v, x, y, cx, cy, data, cx, cy, 0, 0); } } else if (encoding == 1) /* copy rect */ { init_stream(s, 8192); error = lib_recv(v, s->data, 4); if (error == 0) { in_uint16_be(s, srcx); in_uint16_be(s, srcy); error = v->server_screen_blt(v, x, y, cx, cy, srcx, srcy); } } else if (encoding == 0xffffff11) /* cursor */ { g_memset(cursor_data, 0, 32 * (32 * 3)); g_memset(cursor_mask, 0, 32 * (32 / 8)); j = cx * cy * Bpp; k = ((cx + 7) / 8) * cy; init_stream(s, j + k); error = lib_recv(v, s->data, j + k); if (error == 0) { in_uint8p(s, d1, j); in_uint8p(s, d2, k); for (j = 0; j < 32; j++) { for (k = 0; k < 32; k++) { pixel = get_pixel_safe(d2, k, 31 - j, cx, cy, 1); set_pixel_safe(cursor_mask, k, j, 32, 32, 1, !pixel); if (pixel) { pixel = get_pixel_safe(d1, k, 31 - j, cx, cy, v->mod_bpp); split_color(pixel, &r, &g, &b, v->mod_bpp, v->palette); pixel = make_color(r, g, b, 24); set_pixel_safe(cursor_data, k, j, 32, 32, 24, pixel); } } } /* keep these in 32x32, vnc cursor can be alot bigger */ if (x > 31) { x = 31; } if (y > 31) { y = 31; } error = v->server_set_cursor(v, x, y, cursor_data, cursor_mask); } } else if (encoding == 0xffffff21) /* desktop size */ { v->mod_width = cx; v->mod_height = cy; error = v->server_reset(v, cx, cy, v->mod_bpp); } else { g_sprintf(text, "error in lib_framebuffer_update encoding = %8.8x", encoding); v->server_msg(v, text, 1); } } } if (error == 0) { error = v->server_end_update(v); } g_free(data); if (error == 0) { /* FrambufferUpdateRequest */ init_stream(s, 8192); out_uint8(s, 3); out_uint8(s, 1); out_uint16_be(s, 0); out_uint16_be(s, 0); out_uint16_be(s, v->mod_width); out_uint16_be(s, v->mod_height); error = lib_send(v, s->data, 10); } free_stream(s); return error; } /******************************************************************************/ int DEFAULT_CC lib_clip_data(struct vnc* v) { struct stream* s; struct stream* out_s; int size; int error; g_free(v->clip_data); v->clip_data = 0; v->clip_data_size = 0; make_stream(s); init_stream(s, 8192); error = lib_recv(v, s->data, 7); if (error == 0) { in_uint8s(s, 3); in_uint32_be(s, size); v->clip_data = (char*)g_malloc(size, 0); v->clip_data_size = size; error = lib_recv(v, v->clip_data, size); } if (error == 0) { make_stream(out_s); init_stream(out_s, 8192); out_uint16_le(out_s, 2); out_uint16_le(out_s, 0); out_uint32_le(out_s, 0x90); out_uint8(out_s, 0x0d); out_uint8s(out_s, 35); out_uint8(out_s, 0x10); out_uint8s(out_s, 35); out_uint8(out_s, 0x01); out_uint8s(out_s, 35); out_uint8(out_s, 0x07); out_uint8s(out_s, 35); out_uint8s(out_s, 4); s_mark_end(out_s); size = (int)(out_s->end - out_s->data); error = v->server_send_to_channel(v, v->clip_chanid, out_s->data, size, size, 3); free_stream(out_s); } free_stream(s); return error; } /******************************************************************************/ int DEFAULT_CC lib_palette_update(struct vnc* v) { struct stream* s; int first_color; int num_colors; int i; int r; int g; int b; int error; make_stream(s); init_stream(s, 8192); error = lib_recv(v, s->data, 5); if (error == 0) { in_uint8s(s, 1); in_uint16_be(s, first_color); in_uint16_be(s, num_colors); init_stream(s, 8192); error = lib_recv(v, s->data, num_colors * 6); } if (error == 0) { for (i = 0; i < num_colors; i++) { in_uint16_be(s, r); in_uint16_be(s, g); in_uint16_be(s, b); r = r >> 8; g = g >> 8; b = b >> 8; v->palette[first_color + i] = (r << 16) | (g << 8) | b; } error = v->server_begin_update(v); } if (error == 0) { error = v->server_palette(v, v->palette); } if (error == 0) { error = v->server_end_update(v); } free_stream(s); return error; } /******************************************************************************/ int DEFAULT_CC lib_bell_trigger(struct vnc* v) { struct stream* s; int error; error = v->server_bell_trigger(v); return error; } /******************************************************************************/ int DEFAULT_CC lib_mod_signal(struct vnc* v) { char type; int error; char text[256]; error = lib_recv(v, &type, 1); if (error == 0) { if (type == 0) /* framebuffer update */ { error = lib_framebuffer_update(v); } else if (type == 1) /* palette */ { error = lib_palette_update(v); } else if (type == 2) /* bell */ { error = lib_bell_trigger(v); } else if (type == 3) /* clipboard */ { g_writeln("got clip data"); error = lib_clip_data(v); } else { g_sprintf(text, "unknown in lib_mod_signal %d", type); v->server_msg(v, text, 1); } } return error; } /******************************************************************************/ int DEFAULT_CC lib_mod_start(struct vnc* v, int w, int h, int bpp) { v->server_begin_update(v); v->server_set_fgcolor(v, 0); v->server_fill_rect(v, 0, 0, w, h); v->server_end_update(v); v->server_width = w; v->server_height = h; v->server_bpp = bpp; return 0; } /******************************************************************************/ static int APP_CC lib_open_clip_channel(struct vnc* v) { char init_data[12] = { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; v->clip_chanid = v->server_get_channel_id(v, "cliprdr"); if (v->clip_chanid >= 0) { v->server_send_to_channel(v, v->clip_chanid, init_data, 12, 12, 3); } return 0; } /******************************************************************************/ /* return error */ int DEFAULT_CC lib_mod_connect(struct vnc* v) { char cursor_data[32 * (32 * 3)]; char cursor_mask[32 * (32 / 8)]; char con_port[256]; char text[256]; struct stream* s; struct stream* pixel_format; int error; int i; int check_sec_result; v->server_msg(v, "started connecting", 0); check_sec_result = 1; /* only support 8 and 16 bpp connections from rdp client */ if ((v->server_bpp != 8) && (v->server_bpp != 15) && (v->server_bpp != 16) && (v->server_bpp != 24)) { v->server_msg(v, "error - only supporting 8, 15, 16 and 24 bpp rdp \ connections", 0); return 1; } if (g_strcmp(v->ip, "") == 0) { v->server_msg(v, "error - no ip set", 0); return 1; } make_stream(s); g_sprintf(con_port, "%s", v->port); make_stream(pixel_format); v->sck = g_tcp_socket(); v->sck_obj = g_create_wait_obj_from_socket(v->sck, 0); v->sck_closed = 0; g_sprintf(text, "connecting to %s %s", v->ip, con_port); v->server_msg(v, text, 0); error = g_tcp_connect(v->sck, v->ip, con_port); if (error == 0) { v->server_msg(v, "tcp connected", 0); g_tcp_set_non_blocking(v->sck); g_tcp_set_no_delay(v->sck); /* protocal version */ init_stream(s, 8192); error = lib_recv(v, s->data, 12); if (error == 0) { error = lib_send(v, "RFB 003.003\n", 12); } /* sec type */ if (error == 0) { init_stream(s, 8192); error = lib_recv(v, s->data, 4); } if (error == 0) { in_uint32_be(s, i); g_sprintf(text, "security level is %d (1 = none, 2 = standard)", i); v->server_msg(v, text, 0); if (i == 1) /* none */ { check_sec_result = 0; } else if (i == 2) /* dec the password and the server random */ { init_stream(s, 8192); error = lib_recv(v, s->data, 16); if (error == 0) { rfbEncryptBytes(s->data, v->password); error = lib_send(v, s->data, 16); } } else { error = 1; } } } if (error == 0 && check_sec_result) { /* sec result */ init_stream(s, 8192); error = lib_recv(v, s->data, 4); if (error == 0) { in_uint32_be(s, i); if (i != 0) { v->server_msg(v, "password failed", 0); error = 2; } else { v->server_msg(v, "password ok", 0); } } } if (error == 0) { v->server_msg(v, "sending share flag", 0); init_stream(s, 8192); s->data[0] = 1; error = lib_send(v, s->data, 1); /* share flag */ } if (error == 0) { v->server_msg(v, "receiving server init", 0); error = lib_recv(v, s->data, 4); /* server init */ } if (error == 0) { in_uint16_be(s, v->mod_width); in_uint16_be(s, v->mod_height); init_stream(pixel_format, 8192); v->server_msg(v, "receiving pixel format", 0); error = lib_recv(v, pixel_format->data, 16); } if (error == 0) { v->mod_bpp = v->server_bpp; init_stream(s, 8192); v->server_msg(v, "receiving name length", 0); error = lib_recv(v, s->data, 4); /* name len */ } if (error == 0) { in_uint32_be(s, i); if (i > 255 || i < 0) { error = 3; } else { v->server_msg(v, "receiving name", 0); error = lib_recv(v, v->mod_name, i); v->mod_name[i] = 0; } } /* should be connected */ if (error == 0) { /* SetPixelFormat */ init_stream(s, 8192); out_uint8(s, 0); out_uint8(s, 0); out_uint8(s, 0); out_uint8(s, 0); init_stream(pixel_format, 8192); if (v->mod_bpp == 8) { out_uint8(pixel_format, 8); /* bits per pixel */ out_uint8(pixel_format, 8); /* depth */ #if defined(B_ENDIAN) out_uint8(pixel_format, 1); /* big endian */ #else out_uint8(pixel_format, 0); /* big endian */ #endif out_uint8(pixel_format, 0); /* true color flag */ out_uint16_be(pixel_format, 0); /* red max */ out_uint16_be(pixel_format, 0); /* green max */ out_uint16_be(pixel_format, 0); /* blue max */ out_uint8(pixel_format, 0); /* red shift */ out_uint8(pixel_format, 0); /* green shift */ out_uint8(pixel_format, 0); /* blue shift */ out_uint8s(pixel_format, 3); /* pad */ } else if (v->mod_bpp == 15) { out_uint8(pixel_format, 16); /* bits per pixel */ out_uint8(pixel_format, 15); /* depth */ #if defined(B_ENDIAN) out_uint8(pixel_format, 1); /* big endian */ #else out_uint8(pixel_format, 0); /* big endian */ #endif out_uint8(pixel_format, 1); /* true color flag */ out_uint16_be(pixel_format, 31); /* red max */ out_uint16_be(pixel_format, 31); /* green max */ out_uint16_be(pixel_format, 31); /* blue max */ out_uint8(pixel_format, 10); /* red shift */ out_uint8(pixel_format, 5); /* green shift */ out_uint8(pixel_format, 0); /* blue shift */ out_uint8s(pixel_format, 3); /* pad */ } else if (v->mod_bpp == 16) { out_uint8(pixel_format, 16); /* bits per pixel */ out_uint8(pixel_format, 16); /* depth */ #if defined(B_ENDIAN) out_uint8(pixel_format, 1); /* big endian */ #else out_uint8(pixel_format, 0); /* big endian */ #endif out_uint8(pixel_format, 1); /* true color flag */ out_uint16_be(pixel_format, 31); /* red max */ out_uint16_be(pixel_format, 63); /* green max */ out_uint16_be(pixel_format, 31); /* blue max */ out_uint8(pixel_format, 11); /* red shift */ out_uint8(pixel_format, 5); /* green shift */ out_uint8(pixel_format, 0); /* blue shift */ out_uint8s(pixel_format, 3); /* pad */ } else if (v->mod_bpp == 24) { out_uint8(pixel_format, 32); /* bits per pixel */ out_uint8(pixel_format, 24); /* depth */ #if defined(B_ENDIAN) out_uint8(pixel_format, 1); /* big endian */ #else out_uint8(pixel_format, 0); /* big endian */ #endif out_uint8(pixel_format, 1); /* true color flag */ out_uint16_be(pixel_format, 255); /* red max */ out_uint16_be(pixel_format, 255); /* green max */ out_uint16_be(pixel_format, 255); /* blue max */ out_uint8(pixel_format, 16); /* red shift */ out_uint8(pixel_format, 8); /* green shift */ out_uint8(pixel_format, 0); /* blue shift */ out_uint8s(pixel_format, 3); /* pad */ } out_uint8a(s, pixel_format->data, 16); v->server_msg(v, "sending pixel format", 0); error = lib_send(v, s->data, 20); } if (error == 0) { /* SetEncodings */ init_stream(s, 8192); out_uint8(s, 2); out_uint8(s, 0); out_uint16_be(s, 4); out_uint32_be(s, 0); /* raw */ out_uint32_be(s, 1); /* copy rect */ out_uint32_be(s, 0xffffff11); /* cursor */ out_uint32_be(s, 0xffffff21); /* desktop size */ v->server_msg(v, "sending encodings", 0); error = lib_send(v, s->data, 4 + 4 * 4); } if (error == 0) { error = v->server_reset(v, v->mod_width, v->mod_height, v->mod_bpp); } if (error == 0) { /* FrambufferUpdateRequest */ init_stream(s, 8192); out_uint8(s, 3); out_uint8(s, 0); out_uint16_be(s, 0); out_uint16_be(s, 0); out_uint16_be(s, v->mod_width); out_uint16_be(s, v->mod_height); v->server_msg(v, "sending framebuffer update request", 0); error = lib_send(v, s->data, 10); } if (error == 0) { if (v->server_bpp != v->mod_bpp) { v->server_msg(v, "error - server bpp and client bpp do not match", 0); error = 1; } } if (error == 0) { /* set almost null cursor, this is the little dot cursor */ g_memset(cursor_data, 0, 32 * (32 * 3)); g_memset(cursor_data + (32 * (32 * 3) - 1 * 32 * 3), 0xff, 9); g_memset(cursor_data + (32 * (32 * 3) - 2 * 32 * 3), 0xff, 9); g_memset(cursor_data + (32 * (32 * 3) - 3 * 32 * 3), 0xff, 9); g_memset(cursor_mask, 0xff, 32 * (32 / 8)); v->server_msg(v, "sending cursor", 0); error = v->server_set_cursor(v, 3, 3, cursor_data, cursor_mask); } free_stream(s); free_stream(pixel_format); if (error == 0) { v->server_msg(v, "connection complete, connected ok", 0); lib_open_clip_channel(v); } else { v->server_msg(v, "error - problem connecting", 0); } return error; } /******************************************************************************/ int DEFAULT_CC lib_mod_end(struct vnc* v) { if (v->vnc_desktop != 0) { } g_free(v->clip_data); v->clip_data = 0; v->clip_data_size = 0; return 0; } /******************************************************************************/ int DEFAULT_CC lib_mod_set_param(struct vnc* v, char* name, char* value) { if (g_strcasecmp(name, "username") == 0) { g_strncpy(v->username, value, 255); } else if (g_strcasecmp(name, "password") == 0) { g_strncpy(v->password, value, 255); } else if (g_strcasecmp(name, "ip") == 0) { g_strncpy(v->ip, value, 255); } else if (g_strcasecmp(name, "port") == 0) { g_strncpy(v->port, value, 255); } else if (g_strcasecmp(name, "keylayout") == 0) { v->keylayout = g_atoi(value); } return 0; } /******************************************************************************/ /* return error */ int DEFAULT_CC lib_mod_get_wait_objs(struct vnc* v, tbus* read_objs, int* rcount, tbus* write_objs, int* wcount, int* timeout) { int i; i = *rcount; if (v != 0) { if (v->sck_obj != 0) { read_objs[i++] = v->sck_obj; } } *rcount = i; return 0; } /******************************************************************************/ /* return error */ int DEFAULT_CC lib_mod_check_wait_objs(struct vnc* v) { int rv; rv = 0; if (v != 0) { if (v->sck_obj != 0) { if (g_is_wait_obj_set(v->sck_obj)) { rv = lib_mod_signal(v); } } } return rv; } /******************************************************************************/ struct vnc* EXPORT_CC mod_init(void) { struct vnc* v; v = (struct vnc*)g_malloc(sizeof(struct vnc), 1); /* set client functions */ v->size = sizeof(struct vnc); v->version = CURRENT_MOD_VER; v->handle = (long)v; v->mod_connect = lib_mod_connect; v->mod_start = lib_mod_start; v->mod_event = lib_mod_event; v->mod_signal = lib_mod_signal; v->mod_end = lib_mod_end; v->mod_set_param = lib_mod_set_param; v->mod_get_wait_objs = lib_mod_get_wait_objs; v->mod_check_wait_objs = lib_mod_check_wait_objs; return v; } /******************************************************************************/ int EXPORT_CC mod_exit(struct vnc* v) { if (v == 0) { return 0; } g_delete_wait_obj_from_socket(v->sck_obj); g_tcp_close(v->sck); g_free(v); return 0; } xrdp-0.6.0/vnc/vnc.h000066400000000000000000000112741203155130500142170ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2004-2010 libvnc */ /* include other h files */ #include "arch.h" #include "parse.h" #include "os_calls.h" #include "d3des.h" #include "defines.h" #define CURRENT_MOD_VER 2 struct vnc { int size; /* size of this struct */ int version; /* internal version */ /* client functions */ int (*mod_start)(struct vnc* v, int w, int h, int bpp); int (*mod_connect)(struct vnc* v); int (*mod_event)(struct vnc* v, int msg, long param1, long param2, long param3, long param4); int (*mod_signal)(struct vnc* v); int (*mod_end)(struct vnc* v); int (*mod_set_param)(struct vnc* v, char* name, char* value); int (*mod_session_change)(struct vnc* v, int, int); int (*mod_get_wait_objs)(struct vnc* v, tbus* read_objs, int* rcount, tbus* write_objs, int* wcount, int* timeout); int (*mod_check_wait_objs)(struct vnc* v); long mod_dumby[100 - 9]; /* align, 100 minus the number of mod functions above */ /* server functions */ int (*server_begin_update)(struct vnc* v); int (*server_end_update)(struct vnc* v); int (*server_fill_rect)(struct vnc* v, int x, int y, int cx, int cy); int (*server_screen_blt)(struct vnc* v, int x, int y, int cx, int cy, int srcx, int srcy); int (*server_paint_rect)(struct vnc* v, int x, int y, int cx, int cy, char* data, int width, int height, int srcx, int srcy); int (*server_set_cursor)(struct vnc* v, int x, int y, char* data, char* mask); int (*server_palette)(struct vnc* v, int* palette); int (*server_msg)(struct vnc* v, char* msg, int code); int (*server_is_term)(struct vnc* v); int (*server_set_clip)(struct vnc* v, int x, int y, int cx, int cy); int (*server_reset_clip)(struct vnc* v); int (*server_set_fgcolor)(struct vnc* v, int fgcolor); int (*server_set_bgcolor)(struct vnc* v, int bgcolor); int (*server_set_opcode)(struct vnc* v, int opcode); int (*server_set_mixmode)(struct vnc* v, int mixmode); int (*server_set_brush)(struct vnc* v, int x_orgin, int y_orgin, int style, char* pattern); int (*server_set_pen)(struct vnc* v, int style, int width); int (*server_draw_line)(struct vnc* v, int x1, int y1, int x2, int y2); int (*server_add_char)(struct vnc* v, int font, int charactor, int offset, int baseline, int width, int height, char* data); int (*server_draw_text)(struct vnc* v, int font, int flags, int mixmode, int clip_left, int clip_top, int clip_right, int clip_bottom, int box_left, int box_top, int box_right, int box_bottom, int x, int y, char* data, int data_len); int (*server_reset)(struct vnc* v, int width, int height, int bpp); int (*server_query_channel)(struct vnc* v, int index, char* channel_name, int* channel_flags); int (*server_get_channel_id)(struct vnc* v, char* name); int (*server_send_to_channel)(struct vnc* v, int channel_id, char* data, int data_len, int total_data_len, int flags); int (*server_bell_trigger)(struct vnc* v); long server_dumby[100 - 25]; /* align, 100 minus the number of server functions above */ /* common */ long handle; /* pointer to self as long */ long wm; long painter; int sck; /* mod data */ int server_width; int server_height; int server_bpp; int mod_width; int mod_height; int mod_bpp; char mod_name[256]; int mod_mouse_state; int palette[256]; int vnc_desktop; char username[256]; char password[256]; char ip[256]; char port[256]; int sck_closed; int shift_state; /* 0 up, 1 down */ int keylayout; int clip_chanid; char* clip_data; int clip_data_size; tbus sck_obj; }; xrdp-0.6.0/xrdp/000077500000000000000000000000001203155130500134425ustar00rootroot00000000000000xrdp-0.6.0/xrdp/Makefile.am000066400000000000000000000022121203155130500154730ustar00rootroot00000000000000EXTRA_DIST = xrdp.ini rsakeys.ini ad24b.bmp ad256.bmp xrdp24b.bmp xrdp256.bmp sans-10.fv1 cursor0.cur cursor1.cur xrdp.h xrdp_types.h if XRDP_DEBUG EXTRA_DEFINES = -DXRDP_DEBUG else EXTRA_DEFINES = -DXRDP_NODEBUG endif AM_CFLAGS = \ -DXRDP_CFG_PATH=\"${sysconfdir}/xrdp\" \ -DXRDP_SBIN_PATH=\"${sbindir}\" \ -DXRDP_SHARE_PATH=\"${datadir}/xrdp\" \ -DXRDP_PID_PATH=\"${localstatedir}/run\" \ $(EXTRA_DEFINES) INCLUDES = \ -I$(top_srcdir)/common \ -I$(top_srcdir)/libxrdp sbin_PROGRAMS = \ xrdp xrdp_SOURCES = \ funcs.c \ lang.c \ xrdp_bitmap.c \ xrdp.c \ xrdp_cache.c \ xrdp_font.c \ xrdp_listen.c \ xrdp_login_wnd.c \ xrdp_mm.c \ xrdp_painter.c \ xrdp_process.c \ xrdp_region.c \ xrdp_wm.c xrdp_LDADD = \ $(top_srcdir)/common/libcommon.la \ $(top_srcdir)/libxrdp/libxrdp.la xrdpsysconfdir=$(sysconfdir)/xrdp xrdpsysconf_DATA = \ xrdp.ini \ rsakeys.ini xrdppkgdatadir=$(datadir)/xrdp xrdppkgdata_DATA = \ ad24b.bmp \ ad256.bmp \ xrdp24b.bmp \ xrdp256.bmp \ sans-10.fv1 \ cursor0.cur \ cursor1.cur # must be tab below install-data-hook: chmod 600 $(DESTDIR)$(sysconfdir)/xrdp/rsakeys.ini xrdp-0.6.0/xrdp/ad24b.bmp000066400000000000000000001627461203155130500150560ustar00rootroot00000000000000BMæå6(ŒŒ°å  ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀ™™™fffffffff333ffffff™™™ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀffffffÌ™fÌ™fÿ™™ÿ™™ÿ™™Ì™f™ffffffff™™™ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀ™™™ffffffffffff™™™ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀffffff™ffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™Ì™ffff™™™ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀfffffff™ffÌffÌ™fÌff™fffffffÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀ™™™333fffÌ™fÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™ffff™™™ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀ™™™™™™™™™ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀfffffff™f™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™f™ffffÀÀÀÀÀÀÀÀÀÀÀÀfffffff33™ffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ffffffÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀ™™™fffff™ff™ffffff™™™ÀÀÀÀÀÀÀÀÀÀÀÀ™™™fff333f™f™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™f™ffff™™™™™™fffÌ™f™fffffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™ffffffffffÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀ™™™ffffff™™ÌÌÌÿÌÌÿÌÌÿ™™ÿff™fffÀÀÀÀÀÀffffffffffff™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™f™f3f3ffffffÿ™fÿ™™fffÌ™fÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™Ì™ffff™ffÿ™™™ff™™™ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀfffffffff™™ÌÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿ™™Ìffffffffff™f™Ì™ffff™f™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™f™f3fff™ffffÿ™™ÿ™™ÿ™™333ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™Ì™ffff™ffÿ™™ÿ™™ÿ™™fff™™™ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀ™™™ff™™™™fffÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿ™™Ìfffff™ffffff™Ì™™Ì™ffffÌf™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™f™fffffÌffffÌ™fÿ™™ÿ™™Ì™ffffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™Ì™fff3™ffÿ™™ÿ™™ÿ™™ÿ™™Ì™ffffÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀfff™™ÿff™ff™ÌÌÿÌÌÿÌÌÿÌÌÿ™™Ìfffff™ÌÌÿfff™Ì™™Ì™™Ì™333™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™ffffff™Ì™f™f™ffÿ™™ÿ™™ÿ™™Ì™ffffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™Ì™fff3Ì™fÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™Ì™ffffÀÀÀÀÀÀÀÀÀÀÀÀ™™™™™™™™™ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀ™™™ff™ÌÌÿff™fffÌÌÿÌÌÿÌÌÿ™™Ìfff™™™ÌÌÿ™™Ìfff™Ì™™Ì™™Ì™ffffÌf™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™ffffff™Ì™™Ì™fffÌ™fÿ™™ÿ™™ÿ™™Ì™ffffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™Ì™fff3Ì™fÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™™fffffÀÀÀÀÀÀfffffff™ff™fffffffÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀ™™™fffff3ffffff™™™ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀfff™™™ÌÌÿ™™ÌfffÌÌÿÌÌÿ™™Ìfff™™ÌÌÌÿÌÌÿ™™Ìfff™Ì™™Ì™™Ì™ffff™f™Ì™™Ì™™Ì™™Ì™™Ì™ffffff™Ì™™Ì™™Ì™ff3ÿ™™ÿ™™ÿ™™ÿ™™ÿ™ff33ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™™ffff3Ì™fÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™™fffff3f3fff™Ì™™Ì™™Ì™™Ì™f™ffffÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀffffffÌ™fÿ™™ÿ™™ÿ™f™fffff™™™ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀ™™™ff™ÌÌÿ™™ÿfff™™™™™™fff™™ÌÌÌÿÌÌÿÌÌÿff™f™f™Ì™™Ì™™Ì™f™ffff™Ì™™Ì™™Ì™™Ì™ffffff™Ì™™Ì™™Ì™f™ffffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ff3Ì™fÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™™fffffÌ™fÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™fffffffff™Ì™™Ì™™Ì™™Ì™™Ì™f™ffffÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀ™™™fff333fffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™fff™™™ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀ™™™fffÌÌÿÌÌÿ™™Ìffffff™™ÌÌÌÿÌÌÿÌÌÿÌÌÿ™™Ìfff™Ì™™Ì™™Ì™™Ì™3f3fÌf™Ì™™Ì™ffffff™Ì™™Ì™™Ì™™Ì™f™f™ffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™fff™ffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™™fffffÿ™fÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™ffffffffff™Ì™™Ì™™Ì™™Ì™™Ì™fff™™™ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀ™ffffffff333fffff3Ì™fÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™fff™™™ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀfff™™™ff™fffffffffÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿ™™ÿfff™Ì™™Ì™™Ì™™Ì™f™ffff™Ì™ffffff™Ì™™Ì™™Ì™™Ì™™Ì™f™ffffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™™fffffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ffffffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™Ì™ffffffff™f™Ì™™Ì™™Ì™™Ì™fÌ™fffÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀ™™™ffffff™ffÿ™fffffffÿ™™™fffffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™fffÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀ™™™333fff™™Ì™™ÿffffffÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿffffÌf™Ì™™Ì™™Ì™™Ì™fff333f™f™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™fffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™fff™ffÿ™™ÿ™™ÿ™™ffffffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™Ì™ffff3f3f™f™Ì™™Ì™™Ì™™Ì™fffÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀfff™ffÌ™fÿ™™ÿ™™™fffffÿ™™ÿ™™ÿ™™fff™ffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™™ff™™™ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀ™™™fff™™ÿÌÌÿ™™Ìfffff™ÌÌÿÌÌÿÌÌÿÌÌÿ™™Ìfff™Ì™™Ì™f™ffff3ff333fÌ™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™fffÿ™fÿ™™ÿ™™ÿ™™ÿ™™ÿ™™Ì™fff3ÿ™™ÿ™fffffffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™™fffff3f3™Ì™™Ì™™Ì™™Ì™fff™™™ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀfff™ffÿ™™ÿ™™ÿ™™™fffffÿ™fÿ™™ÿ™™ÿ™™ÿ™™fff™ffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™fffÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀ™™™fff™™ÿÌÌÿ™™Ìfff™™™ÌÌÿÌÌÿÌÌÿÌÌÿfffffffffffff™f™Ì™f™f3f3™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™fffÌ™fÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™™fffffffffffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™fffffffff™Ì™™Ì™™Ì™f™f™™™ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀfff™ffÿ™™ÿ™™ÿ™™Ì™fff3Ì™fÿ™™ÿ™™ÿ™™ÿ™™ÿ™™Ì™fff3Ì™fÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™™ff™™™ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀfffff™ÌÌÿÌÌÿ™™Ìfff™™ÌÌÌÿÌÌÿÌÌÿ™™Ì3f3fff™Ì™™Ì™™Ì™™Ì™f™ffff™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™f™ffffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™™ff333fffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™fffffffff™Ì™™Ì™f™f™™™ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀ™™™fffÿ™™ÿ™™ÿ™™Ì™fff3Ì™fÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™Ìfffffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™Ì™ffffÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀfffff™ÌÌÿÌÌÿ™™Ìfff™™ÌÌÌÿÌÌÿÌÌÿ™™Ìfff™Ì™™Ì™™Ì™™Ì™™Ì™ffffff™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™fff™ffÿ™™ÿ™™ÿ™f™ffff3fff™ffff3Ì™fÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™Ì™ffffffff™f™Ì™f™f™™™ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀ™™™fffÿ™™ÿ™™ÿ™™Ì™fff3™ffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™™fffffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™Ì™ffffÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀfff™™™ÌÌÿÌÌÿ™™™fff™™ÌÌÌÿÌÌÿÌÌÿ™™Ìfff™Ì™™Ì™™Ì™™Ì™™Ì™ffffff™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™fffÌ™f™ffff3fffÌ™fÿ™™ÿ™™™fffffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™Ì™ffff3f3fÌffffÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀ™™™fffÿ™™ÿ™™ÿ™™Ì™ffff™ffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™fff™ffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™fffÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀfff™™ÌÌÌÿÌÌÿff™fff™™ÿÌÌÿÌÌÿÌÌÿ™™™fff™Ì™™Ì™™Ì™™Ì™™Ì™ffffff™Ì™™Ì™™Ì™™Ì™™Ì™f™fff3fffÌ™fÿ™™ÿ™™ÿ™™ÿ™™ÿ™™™fffffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™™fffff333fffÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀ™™™fffÌ™fÿ™™ÿ™™ÿ™™ffffffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™fff3Ì™fÿ™™ÿ™™ÿ™™ÿ™™333ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀfff™™ÌÌÌÿÌÌÿff™fffÌÌÿÌÌÿÌÌÿÌÌÿff™fff™Ì™™Ì™™Ì™™Ì™™Ì™ffff™f™Ì™™Ì™™Ì™™Ì™™Ì™fff™ffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ffffffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™fffff3ÌÌÌÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀfffÌ™fÿ™™ÿ™™ÿ™™ffffffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™Ì™fff3Ì™fÿ™™ÿ™™ÿ™™fffÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀfff™™ÌÌÌÿ™™ÿffffffÌÌÿÌÌÿÌÌÿÌÌÿffffff™Ì™™Ì™™Ì™™Ì™™Ì™3f3f™f™Ì™™Ì™™Ì™™Ì™™Ì™fff™ffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ffffffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™fff™™™ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀfffÌ™fÿ™™ÿ™™ÿ™™ffffffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™™fffffÿ™™ÿ™™Ì™ffffÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀfff™™ÌÌÌÿ™™ÿffffffÌÌÿÌÌÿÌÌÿ™™ÿffff™f™Ì™™Ì™™Ì™™Ì™fÌf3f3f™f™Ì™™Ì™™Ì™™Ì™™Ì™fffÌ™fÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™ffff™ffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™Ì™ffffÌÌÌÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀfffÌ™fÿ™™ÿ™™ÿ™™™fffffÿ™fÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™fff™ffÿ™™™ff™™™ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀ™™™fff™™ÿÌÌÿ™™ÿfffff™ÌÌÿÌÌÿÌÌÿ™™ÿffff™f™Ì™™Ì™™Ì™™Ì™f™f3f3fÌ™™Ì™™Ì™™Ì™™Ì™™Ì™fffÌ™fÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™Ì™fff3™ffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™Ì™ffffÌÌÌÀÀÀÀÀÀÀÀÀÀÀÀfffÌ™fÿ™™ÿ™™ÿ™™™fffffÌ™fÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™fff™fffffÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀ™™™fff™™ÿÌÌÿ™™Ìfff™™™ÌÌÿÌÌÿÌÌÿ™™Ìffff™f™Ì™™Ì™™Ì™™Ì™f™ffff™Ì™™Ì™™Ì™™Ì™™Ì™fÌ™fffÌ™fÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™Ì™fff3Ì™fÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™™fffffÌÌÌÀÀÀÌÌÌfff™ffÿ™™ÿ™™ÿ™™Ì™fff3Ì™fÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™Ì™ff33fffÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀ™™™fff™™ÿ™™ÿ™™™33fff™ÌÌÿÌÌÿÌÌÿ™™ÌffffÌf™Ì™™Ì™™Ì™™Ì™f™ffff™Ì™™Ì™™Ì™™Ì™™Ì™f™ffffÌ™fÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™Ì™fff3Ì™fÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™™ff™ffÀÀÀfff™ffÿ™™ÿ™™ÿ™™Ì™fff3Ì™fÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™Ì™ffffÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀffffff333ffffffff™ÌÌÿÌÌÿÌÌÿÌÌÿ™™ÌffffÌ™™Ì™™Ì™™Ì™™Ì™ffffff™Ì™™Ì™™Ì™™Ì™™Ì™f™ffffÿ™fÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™™ffff3Ì™fÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ffffff™ffÿ™™ÿ™™ÿ™™Ì™fff3™ffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™Ì™ffffÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀfffff™™™Ìfffff™ÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿ™™Ìfff™Ì™™Ì™™Ì™™Ì™™Ì™ffffff™Ì™™Ì™™Ì™™Ì™™Ì™f™ffffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™™fffffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™Ì™ff33Ì™fÿ™™ÿ™™ÿ™ffff™ffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™fff™™™ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀfff™™™™™ÿffffffÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿ™™Ìfff™Ì™™Ì™™Ì™™Ì™™Ì™ffffff™Ì™™Ì™™Ì™™Ì™™Ì™f™ffffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™™fffffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™™ffff3Ì™fÿ™™ffffffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™™ff™™™ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀfff™™™™™ÿffffffÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿf™™fff™Ì™™Ì™™Ì™™Ì™™Ì™ffff™f™Ì™™Ì™™Ì™™Ì™™Ì™fff™ffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ffffffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™™fffffffffffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™™fffffÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀfffff™ÌÌÿffffff™™ÿÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿff™fff™Ì™™Ì™™Ì™™Ì™™Ì™3f3f™f™Ì™™Ì™™Ì™™Ì™™Ì™fff™ffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ffffffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ffffffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™Ì™ffffÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀff™ff™ÌÌÿff™fff™™ÿÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿffffff™Ì™™Ì™™Ì™™Ì™fÌf3f3f™f™Ì™™Ì™™Ì™™Ì™™Ì™fff™ffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™ffff™ffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™fÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™ffffÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀ™™™fff™™ÿ™™™fff™™ÌÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿ™™ÿÌÌÿÌÌÿÌÌÿ™™ÿffff™f™Ì™™Ì™™Ì™™Ì™f™f3f3fÌ™™Ì™™Ì™™Ì™™Ì™™Ì™fffÌ™fÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™Ì™fff3™ffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™fff™™™ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀ™™™fff™™ÿ™™Ìfff™™ÌÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿ™™ÿfff™™™ÌÌÿÌÌÿÌÌÿ™™ÿffff™f™Ì™™Ì™™Ì™™Ì™f™ffff™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™fffÌ™fÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™Ì™fff3Ì™fÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™™fffffÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀ™™™fff™™Ì™™Ìfff™™ÌÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿfffffffff™™ÌÌÌÿÌÌÿÌÌÿ™™Ìffff™f™Ì™™Ì™fÌff™f3f33f3™Ì™™Ì™™Ì™™Ì™™Ì™fÌ™fffÌ™fÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™Ì™fff3Ì™fÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™Ì™ffffÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀfff™™Ì™™Ìfffff™ÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿff™fff™™ÿ™™Ìfff™™ÌÌÌÿÌÌÿÌÌÿ™™Ìffffff333ffffff333f™f™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™f™ffffÌ™fÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™™ffff3Ì™fÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™Ì™ffffÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀfff™™Ì™™ÿfffff™ÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿ™™Ìffffff™™ÿÌÌÿ™™™fff™™ÿÌÌÿÌÌÿ™™™ffff™f™Ì™™Ì™ffffff™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™f™ffffÿ™fÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™™fffffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™fff™™™ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀfff™™Ì™™ÿffffffÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿ™™ÿfff™™™™™™fffÌÌÿÌÌÿff™fffÌÌÿ™™Ìfff™Ì™™Ì™™Ì™ffffff™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™f™ffffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™™fffffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™fff™™™ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀfff™™ÌÌÌÿffffffÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿff™™™™ÀÀÀÀÀÀfffff™ÌÌÿ™™ÿffffffffffÌ™™Ì™™Ì™ffffff™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™f™ffffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ffffffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™™fffffÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀfffffffffffffff™™ÿÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿ™™™fffÀÀÀÀÀÀÀÀÀÀÀÀfffff™ÌÌÿ™™Ì3f3fÌf™Ì™™Ì™ffffff™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™fff™ffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ffffffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™Ì™ffffÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀ™™™fff™™Ì™™Ì333fffff™ÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿ™™ÌfffÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀfffff™ffff™f™Ì™™Ì™f™ffff™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™fff™ffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™ffff™ffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™Ì™ffffÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀfff™™ÌÌÌÿff™fff™™Ìfffff™ÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿ™™ÌfffÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÌÌÌffff™f™Ì™™Ì™f™f3f3fÌf™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™fff™ffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™Ì™fff3™ffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™fff™™™ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀfffÌÌÿÌÌÿfff™™ÌÌÌÿ™™Ìfffff™ÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿ™™ÿfff™™™ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀffff™f™Ì™™Ì™fÌf3f3f™f™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™fffÌ™fÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™Ì™fff3Ì™fÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™™ff™™™ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀ™™™fffÌÌÿ™™ÌfffÌÌÿÌÌÿÌÌÿ™™Ìfffff™ÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿff™fffÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀffff™f™Ì™™Ì™™Ì™3f3f™f™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™fffÌ™fÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™Ì™fff3Ì™fÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™™fffffÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀfffÌÌÿ™™ÌfffÌÌÿÌÌÿÌÌÿÌÌÿ™™ÌffffffÌÌÿÌÌÿÌÌÿ™™ÌfffÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀ™™™fff™Ì™™Ì™™Ì™ffffff™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™fÌ™fffÌ™fÿ™™ÿ™™ÿ™™ÿ™™Ì™f™fffff333Ì™fÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™Ì™ffffÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀfff™™ÿ™™ÿ33f™™ÿÌÌÿÌÌÿÌÌÿÌÌÿ™™ÌffffffÌÌÿ™™ÌfffÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀ™™™fff™Ì™™Ì™™Ì™ffffff™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™fff™Ì™™Ì™™Ì™™Ì™™Ì™f™ffff™fffffffff33ffffff333fffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™fff™™™ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀfffff™ÌÌÿfff™™™ÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿ™™ÿfffffffff™™™ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀ™™™fff™Ì™™Ì™™Ì™ffffff™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™fff3f3fff™Ì™™Ì™™Ì™™Ì™™Ì™ffffff™ffÌ™fÿ™™ÿ™™ffffffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™™fffffÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀfff™™™™™Ìfff™™ÿÌÌÿÌÌÿÌÌÿÌÌÿÌÌÿ™™Ì333fffÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀ™™™fff™Ì™™Ì™™Ì™f™ffff™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™ffffff™Ì™ffff™f™Ì™™Ì™™Ì™fff™ffÿ™™ÿ™™ÿ™™ÿ™™ffffffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™™ff™™fÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀffffffffffff™™ÌÌÌÿÌÌÿ™™ÿ™™Ìfff™™™ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀffffÌ™™Ì™™Ì™f™ffff™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™f™f3f3™Ì™™Ì™™Ì™3f3f™f™Ì™fff™ffÿ™™ÿ™™ÿ™™ÿ™™ffffffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™fff™™™ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀ™™™™™™fff33fffffffffffff™™™ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀffffÌf™Ì™™Ì™f™f3f3fÌ™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™3f3f™f™Ì™™Ì™™Ì™f™f3f3ffffffÿ™™ÿ™™ÿ™™ÿ™™™ffff3Ì™fÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™ffffÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀffff™f™Ì™™Ì™fÌf3f3f™f™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™fffffffff™Ì™™Ì™™Ì™™Ì™ffffffÿ™™ÿ™™ÿ™™ÿ™™™ffff3Ì™fÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™Ì™ffffÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀffff™f™Ì™™Ì™™Ì™3fff™f™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™f™ffffÀÀÀ™™™fff™Ì™™Ì™f™ffffÿ™™ÿ™™ÿ™™ÿ™™Ì™fff3Ì™fÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™Ì™ffffÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀffff™f™Ì™™Ì™™Ì™ffff™f™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™f™ffffÌÌÌÀÀÀÀÀÀ™™™ffff™ffffÌ™fÿ™™ÿ™™ÿ™™Ì™fff3™ffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™™fffffÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀffff™f™Ì™™Ì™™Ì™ffffff™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™fffÌÌÌÀÀÀÀÀÀÀÀÀÀÀÀffffffÌ™fÿ™™ÿ™™ÿ™™Ì™fff3™ffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™fff™™™ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀfffffffffffff™fffffff™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™fff™™™ÀÀÀÀÀÀÀÀÀÀÀÀÌÌÌfffÌ™fÿ™™ÿ™™ÿ™™ÿ™™ffffffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™fff™™™ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀ™™™ffff™ff™ff™ffff333fff™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™fff™™™ÀÀÀÀÀÀÀÀÀÀÀÀÌÌÌfffÌ™fÿ™™ÿ™™ÿ™™ÿ™™ffffffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™Ì™ffffÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀffff™f™Ì™™Ì™™Ì™ffff™fffffff™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™f™ffffÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀfff™ffÿ™™ÿ™™ÿ™™ÿ™™ffffffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™Ì™ffffÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀ™™™fff™Ì™™Ì™™Ì™f™ffff™Ì™™Ì™ffffff™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™fÌffffÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀfff™ffÿ™™ÿ™™ÿ™™ÿ™™™ffff3ÿ™fÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™™fffffÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀ™™™f™f™Ì™™Ì™™Ì™ffffÌf™Ì™™Ì™™Ì™ffffff™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™fffÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀfff™ffÿ™™ÿ™™ÿ™™ÿ™™™ffff3Ì™fÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™fff™™™ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀffffÌf™Ì™™Ì™™Ì™3f3™Ì™™Ì™™Ì™™Ì™™Ì™ffffff™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™fff™™™ÀÀÀÀÀÀÀÀÀÀÀÀ™™™fffÿ™™ÿ™™ÿ™™ÿ™™Ì™fff3Ì™fÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™Ì™f™ffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™fff™™™ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀfff™Ì™™Ì™™Ì™fÌffff™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™ffffff™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™f™ffffÀÀÀÀÀÀÀÀÀÀÀÀ™™™fffÿ™™ÿ™™ÿ™™ÿ™™Ì™fff3™ffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™fff3f33Ì™fÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™Ì™ffffÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀfff™Ì™™Ì™™Ì™f™ffff™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™ffffff™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™f™ffffÀÀÀÀÀÀÀÀÀÀÀÀ™™™fffÿ™™ÿ™™ÿ™™ÿ™™Ì™ffff™ffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™fff™ffÌ™fff3Ì™fÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™Ì™ffffÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀffffÌ™™Ì™™Ì™f™ffff™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™ffffff™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™fffÀÀÀÀÀÀÀÀÀÀÀÀ™™™fffÌ™fÿ™™ÿ™™ÿ™™ÿ™™ffffffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™™fffffÿ™™ÿ™™™fffffÿ™fÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™™fffffÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀ™™™f™f™Ì™™Ì™™Ì™fff™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™ffffff™Ì™™Ì™™Ì™™Ì™fff™™™ÀÀÀÀÀÀÀÀÀÀÀÀfffÌ™fÿ™™ÿ™™ÿ™™ÿ™™ffffffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™™ffff3Ì™fÿ™™ÿ™™ÿ™™™fffffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™™fffffÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀ™™™fff™Ì™™Ì™™Ì™3f3™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™f™ffff™Ì™™Ì™fff™™™ÀÀÀÀÀÀÀÀÀÀÀÀfffÌ™fÿ™™ÿ™™ÿ™™ÿ™™™fffffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™Ì™fff3Ì™fÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ffffffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™fff™™™ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀffff™f™Ì™™Ì™ffffff™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™f™fffff™ffffÀÀÀÀÀÀÀÀÀÀÀÀfffÌ™fÿ™™ÿ™™ÿ™™ÿ™™™fffffÿ™fÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ffffffÌ™fÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ffffffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™ffff™™™ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀffff™f™Ì™™Ì™3f3f™f™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™ffffffÀÀÀÀÀÀÀÀÀÀÀÀfff™ffÿ™™ÿ™™ÿ™™ÿ™™™ffff3Ì™fÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™™fffffÌÌÌfffÌ™fÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™ffff™ffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™Ì™ffffÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀffffff™Ì™f™fffffÌ™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™™Ì™f™ffffÀÀÀÀÀÀÀÀÀÀÀÀfff™ffÿ™™ÿ™™ÿ™™ÿ™™Ì™fff3Ì™fÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™Ì™ffffÌÌÌÀÀÀÌÌÌfffÌ™fÿ™™ÿ™™ÿ™™ÿ™™ÿ™™Ì™fff3Ì™fÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™Ì™ffffÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀ™™™ffffff3333f3fff™Ì™™Ì™™Ì™™Ì™™Ì™f™fffffffÀÀÀÀÀÀÀÀÀÀÀÀfff™ffÿ™™ÿ™™ÿ™™ÿ™™Ì™fff3™ffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™Ì™ffffÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀfffÌ™fÿ™™ÿ™™ÿ™™ÿ™™ÿ™™Ì™fff3Ì™fÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™™ff333™™™ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀ™™™fff3f33f3fffffffffffffff™™™ÀÀÀÀÀÀÀÀÀÀÀÀ™™™fffÿ™™ÿ™™ÿ™™ÿ™™ÿ™ffff™ffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™fff™™™ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀ™™™fffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™™fffffÿ™fÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™ffff™fffffÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀ™™™™™™ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀ™™™fffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ffffffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™fff™™™ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀ™™™fffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™™fffffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ffffffÿ™™™ff™™™ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀfff333™ff™ffÌ™fÌ™fÿ™™ffffffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™™fffffÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀ™™™fffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ffffffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™™ffff3ÿ™fÿ™™Ì™ffffÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀfff™ff™ffffffff333f33f33Ì™fÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™Ì™ffffÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀfff™ffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ffffffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™fff3Ì™fÿ™™ÿ™™ÿ™ffffÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀfff™ffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™fffffffffÌ™fÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™Ì™ffffÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀfff™ffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™ffff™ffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ffffffÿ™™ÿ™™ÿ™™ÿ™™fffÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀfffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™™fffffÿ™™™fffffÌ™fÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™fff™™™ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀfff™ffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™Ì™fff3Ìffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™™ffff3ÿ™fÿ™™ÿ™™ÿ™™ÿ™™fff™™™ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀfffÌ™fÿ™™ÿ™™ÿ™™ÿ™™Ì™fff3Ì™fÿ™™ÿ™™™ffff3Ì™fÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™™fffffÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀfffÌ™fÿ™™ÿ™™ÿ™™ÿ™™ÿ™™Ì™fff3Ì™fÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™ffffÌ™fÿ™™ÿ™™ÿ™™ÿ™™ÿ™™fff™™™ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀfffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™fff™ffÿ™™ÿ™™ÿ™™ÿ™™Ì™fff3Ì™fÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™Ì™ffffÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀfffÌ™fÿ™™ÿ™™ÿ™™ÿ™™ÿ™™™fffffÌ™fÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ffffffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™fffÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀ™™™fffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™f33ÿ™fÿ™™ÿ™™ÿ™™ÿ™™ÿ™™Ì™fff3Ì™fÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™Ì™ffffÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀfffÌ™fÿ™™ÿ™™ÿ™™ÿ™™ÿ™™™fffffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™™ffff3ÿ™fÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™fffÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀ™™™™ffÿ™™ÿ™™ÿ™™ÿ™™Ì™fff3ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™Ì™fff3Ì™fÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™fff™™™ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀfffÌ™fÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ffffffÿ™™ÿ™™ÿ™™ÿ™™ÿ™fff3Ì™fÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™Ì™ffffÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀfffÌ™fÿ™™ÿ™™ÿ™™ÿ™™Ì™ffffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™Ì™fff3Ì™fÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™fff™™™ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀ™™™fffÿ™fÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ffffffÿ™™ÿ™™ÿ™™ffffffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™™ff™™™ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀfffÌ™fÿ™™ÿ™™ÿ™™ÿ™™™fffffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™Ì™fff3™ffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™™fffffÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀ™™™fffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™ffff™ffÿ™™™ffff3ÿ™fÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™fffÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀfffÌ™fÿ™™ÿ™™ÿ™™ÿ™™™ff™ffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™Ì™fff3™ffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™Ì™ffffÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀ™™™fffÌ™fÌ™fÌ™fÿ™fÿ™™Ì™fff3™ffff3Ì™fÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™™fffffÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀ™™™™ffÿ™™ÿ™™ÿ™™ÿ™™™fffffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™Ì™fff3™ffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™Ì™ffffÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀfff333333ff3ff3ff3ffffffff3fffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™™fffffÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀ™™™fffÿ™™ÿ™™ÿ™™ÿ™™Ì™ffffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™Ì™fff3™ffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™fff™™™ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀ™™™ffffff™ff™ff™ff™ffÌ™fffffffÿ™™ÿ™™ÿ™™ÿ™™Ì™f™fffffÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀfffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™f33ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™Ì™fff3™ffÿ™™ÿ™™ÿ™™ÿ™™™ff™ffÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀ™™™™™™™ffffffffff3333333ffffff™ffffffff™™™ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀfff™ffÿ™™ÿ™™ÿ™™ÿ™™fffÌ™fÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™Ì™ffff™ffÿ™™ÿ™™™fffffÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀ™™™™™™™™™ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀfffÌ™fÿ™™ÿ™™ÿ™™™fffffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™Ì™ffff™ffÌ™ffffÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀfffÌ™fÿ™™ÿ™™ÿ™™fff™ffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™Ì™ffffff3ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀ™™™fffÌ™fÿ™™ÿ™™Ì™fff3Ì™fÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™Ì™ffff™™™ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀ™™™fff™ffÌ™fÿ™™™fffffÌ™fÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™™fffffÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀ™™™ffffff™ffffff33™ffÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™ÿ™™Ì™f™fffffÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀ™™™™™™fff333333fff™ffÌ™fÌ™fÿ™fÌ™f™ffffffff™™™ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀ™™™™™™ffffffffffff™™™ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿxrdp-0.6.0/xrdp/ad256.bmp000077500000000000000000000464661203155130500150060ustar00rootroot00000000000000BM6M¦(ŒŒL  ÿÿÿÿÿÀÀÀ™™™fff333™ffÌ™fÿ™ff33ÿ™™ff3Ìff3f3™Ì™f™ffÌ™ÌÌÌfÌf3ff33f™™ÌÌÌÿ™™ÿ™™fff™f™™                                                                                                                                                                                                                                                                                                                                                                                       xrdp-0.6.0/xrdp/cursor0.cur000066400000000000000000000005061203155130500155530ustar00rootroot00000000000000 0( @€ÿÿÿ€@@€„€É©’ƒà€@€€‚„ˆ À€ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿü?ÿÿü?ÿÿøÿÿxÿÿ0ÿÿÿÿÿÿÿÿÿÿÿ?ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ?ÿÿÿÿÿÿxrdp-0.6.0/xrdp/cursor1.cur000066400000000000000000000005061203155130500155540ustar00rootroot00000000000000 0( @ÿÿÿðð€€€€€€€€€€€€ððÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿáÿÿàÿÿàÿÿüÿÿüÿÿüÿÿüÿÿüÿÿüÿÿüÿÿüÿÿüÿÿüÿÿüÿÿüÿÿàÿÿàÿÿáÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿxrdp-0.6.0/xrdp/czech.txt000066400000000000000000000031031203155130500152740ustar00rootroot00000000000000no shift 003b 002b 011b 0161 010d 0159 017e 00fd 00e1 00ed 0039 003d 00b4 ; + Ä› Å¡ Ä Å™ ž ý á í é = ´ 0071 0071 0065 0072 0074 007a 0075 0069 006f 0070 00fa 0029 00a8 q w e r t z u i o p ú ) ¨ 0061 0073 0064 0066 0067 0068 006a 006b 006c 016f 00a7 a s d f g h j k l ů § 0079 0078 0063 0076 0062 006e 006d 002c 002e 002d y x c v b n m , . - shift 00b0 0031 0032 0033 0034 0035 0036 0037 0038 0039 0030 0025 02c7 ° 1 2 3 4 5 6 7 8 9 0 % ˇ 0051 0057 0045 0052 0054 005a 0055 0049 004f 0050 002f 0028 0027 Q W E R T Z U I O P / ( ' 0041 0053 0044 0046 0047 0048 004a 004b 004c 0022 0021 A S D F G H J K L " ! 0059 0058 0043 0056 0042 004e 004d 003f 003a 005f Y X C V B N M ? : _ altgr 007e 02c7 005e 02d8 00b0 02db 0060 00b7 00b4 02dd 00a8 00b8 ~ ˇ ^ ˘ ° Ë› ` · ´ Ë Â¨ ¸ 005c 007c 20ac 00f7 00d7 00a4 \ | € ÷ × ¤ 0111 0110 005b 005d 0142 0141 0024 00df Ä‘ Ä [ ] Å‚ Å $ ß 0023 0026 0040 007b 007d 003c 003e 002a # & @ { } < > * xrdp-0.6.0/xrdp/funcs.c000066400000000000000000000115371203155130500147330ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2004-2010 simple functions */ #include "xrdp.h" /*****************************************************************************/ /* returns boolean */ int APP_CC rect_contains_pt(struct xrdp_rect* in, int x, int y) { if (x < in->left) { return 0; } if (y < in->top) { return 0; } if (x >= in->right) { return 0; } if (y >= in->bottom) { return 0; } return 1; } /*****************************************************************************/ int APP_CC rect_intersect(struct xrdp_rect* in1, struct xrdp_rect* in2, struct xrdp_rect* out) { int rv; struct xrdp_rect dumby; if (out == 0) { out = &dumby; } *out = *in1; if (in2->left > in1->left) { out->left = in2->left; } if (in2->top > in1->top) { out->top = in2->top; } if (in2->right < in1->right) { out->right = in2->right; } if (in2->bottom < in1->bottom) { out->bottom = in2->bottom; } rv = !ISRECTEMPTY(*out); if (!rv) { g_memset(out, 0, sizeof(struct xrdp_rect)); } return rv; } /*****************************************************************************/ /* returns boolean */ int APP_CC rect_contained_by(struct xrdp_rect* in1, int left, int top, int right, int bottom) { if (left < in1->left || top < in1->top || right > in1->right || bottom > in1->bottom) { return 0; } else { return 1; } } /*****************************************************************************/ /* adjust the bounds to fit in the bitmap */ /* return false if there is nothing to draw else return true */ int APP_CC check_bounds(struct xrdp_bitmap* b, int* x, int* y, int* cx, int* cy) { if (*x >= b->width) { return 0; } if (*y >= b->height) { return 0; } if (*x < 0) { *cx += *x; *x = 0; } if (*y < 0) { *cy += *y; *y = 0; } if (*cx <= 0) { return 0; } if (*cy <= 0) { return 0; } if (*x + *cx > b->width) { *cx = b->width - *x; } if (*y + *cy > b->height) { *cy = b->height - *y; } return 1; } /*****************************************************************************/ /* add a ch at index position in text, index starts at 0 */ /* if index = -1 add it to the end */ int APP_CC add_char_at(char* text, int text_size, twchar ch, int index) { int len; int i; twchar* wstr; len = g_mbstowcs(0, text, 0); wstr = (twchar*)g_malloc((len + 16) * sizeof(twchar), 0); g_mbstowcs(wstr, text, len + 1); if ((index >= len) || (index < 0)) { wstr[len] = ch; wstr[len + 1] = 0; g_wcstombs(text, wstr, text_size); g_free(wstr); return 0; } for (i = (len - 1); i >= index; i--) { wstr[i + 1] = wstr[i]; } wstr[i + 1] = ch; wstr[len + 1] = 0; g_wcstombs(text, wstr, text_size); g_free(wstr); return 0; } /*****************************************************************************/ /* remove a ch at index position in text, index starts at 0 */ /* if index = -1 remove it from the end */ int APP_CC remove_char_at(char* text, int text_size, int index) { int len; int i; twchar* wstr; len = g_mbstowcs(0, text, 0); if (len <= 0) { return 0; } wstr = (twchar*)g_malloc((len + 16) * sizeof(twchar), 0); g_mbstowcs(wstr, text, len + 1); if ((index >= (len - 1)) || (index < 0)) { wstr[len - 1] = 0; g_wcstombs(text, wstr, text_size); g_free(wstr); return 0; } for (i = index; i < (len - 1); i++) { wstr[i] = wstr[i + 1]; } wstr[len - 1] = 0; g_wcstombs(text, wstr, text_size); g_free(wstr); return 0; } /*****************************************************************************/ int APP_CC set_string(char** in_str, const char* in) { if (in_str == 0) { return 0; } g_free(*in_str); *in_str = g_strdup(in); return 0; } /*****************************************************************************/ int APP_CC wchar_repeat(twchar* dest, int dest_size_in_wchars, twchar ch, int repeat) { int index; for (index = 0; index < repeat; index++) { if (index >= dest_size_in_wchars) { break; } dest[index] = ch; } return 0; } xrdp-0.6.0/xrdp/lang.c000066400000000000000000000174721203155130500145420ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2006-2010 keylayout maximum unicode 19996(0x4e00) */ #include "xrdp.h" /* map for rdp to x11 scancodes code1 is regular scancode, code2 is extended scancode */ struct codepair { tui8 code1; tui8 code2; }; static struct codepair g_map[] = { { 0, 0 }, { 9, 0 }, { 10, 0 }, { 11, 0 }, { 12, 0 }, /* 0 - 4 */ { 13, 0 }, { 14, 0 }, { 15, 0 }, { 16, 0 }, { 17, 0 }, /* 5 - 9 */ { 18, 0 }, { 19, 0 }, { 20, 0 }, { 21, 0 }, { 22, 0 }, /* 10 - 14 */ { 23, 0 }, { 24, 0 }, { 25, 0 }, { 26, 0 }, { 27, 0 }, /* 15 - 19 */ { 28, 0 }, { 29, 0 }, { 30, 0 }, { 31, 0 }, { 32, 0 }, /* 20 - 24 */ { 33, 0 }, { 34, 0 }, { 35, 0 }, { 36, 108 }, { 37, 109 }, /* 25 - 29 */ { 38, 0 }, { 39, 0 }, { 40, 0 }, { 41, 0 }, { 42, 0 }, /* 30 - 34 */ { 43, 0 }, { 44, 0 }, { 45, 0 }, { 46, 0 }, { 47, 0 }, /* 35 - 39 */ { 48, 0 }, { 49, 0 }, { 50, 0 }, { 51, 0 }, { 52, 0 }, /* 40 - 44 */ { 53, 0 }, { 54, 0 }, { 55, 0 }, { 56, 0 }, { 57, 0 }, /* 45 - 49 */ { 58, 0 }, { 59, 0 }, { 60, 0 }, { 61, 112 }, { 62, 0 }, /* 50 - 54 */ { 63, 111 }, { 64, 113 }, { 65, 0 }, { 66, 0 }, { 67, 0 }, /* 55 - 59 */ { 68, 0 }, { 69, 0 }, { 70, 0 }, { 71, 0 }, { 72, 0 }, /* 60 - 64 */ { 73, 0 }, { 74, 0 }, { 75, 0 }, { 76, 0 }, { 77, 0 }, /* 65 - 69 */ { 78, 0 }, { 79, 97 }, { 80, 98 }, { 81, 99 }, { 82, 0 }, /* 70 - 74 */ { 83, 100 }, { 84, 0 }, { 85, 102 }, { 86, 0 }, { 87, 103 }, /* 75 - 79 */ { 88, 104 }, { 89, 105 }, { 90, 106 }, { 91, 107 }, { 92, 0 }, /* 80 - 84 */ { 93, 0 }, { 94, 0 }, { 95, 0 }, { 96, 0 }, { 97, 0 }, /* 85 - 89 */ { 98, 0 }, { 0, 115 }, { 0, 116 }, { 0, 117 }, { 102, 0 }, /* 90 - 94 */ { 103, 0 }, { 104, 0 }, { 105, 0 }, { 106, 0 }, { 107, 0 }, /* 95 - 99 */ { 108, 0 }, { 109, 0 }, { 110, 0 }, { 111, 0 }, { 112, 0 }, /* 100 - 104 */ { 113, 0 }, { 114, 0 }, { 115, 0 }, { 116, 0 }, { 117, 0 }, /* 105 - 109 */ { 118, 0 }, { 119, 0 }, { 120, 0 }, { 121, 0 }, { 122, 0 }, /* 110 - 114 */ { 123, 0 }, { 124, 0 }, { 125, 0 }, { 126, 0 }, { 127, 0 }, /* 115 - 119 */ { 128, 0 }, { 129, 0 }, { 130, 0 }, { 131, 0 }, { 132, 0 }, /* 120 - 124 */ { 133, 0 }, { 134, 0 }, { 135, 0 } /* 125 - 127 */ }; /*****************************************************************************/ struct xrdp_key_info* APP_CC get_key_info_from_scan_code(int device_flags, int scan_code, int* keys, int caps_lock, int num_lock, int scroll_lock, struct xrdp_keymap* keymap) { struct xrdp_key_info* rv; int shift; int altgr; int ext; int index; ext = device_flags & KBD_FLAG_EXT; /* 0x0100 */ shift = keys[42] || keys[54]; altgr = keys[56] & KBD_FLAG_EXT; /* right alt */ rv = 0; scan_code = scan_code & 0x7f; index = ext ? g_map[scan_code].code2 : g_map[scan_code].code1; /* keymap file is created with numlock off so we have to do this */ if ((index >= 79) && (index <= 91)) { if (num_lock) { rv = &(keymap->keys_shift[index]); } else { rv = &(keymap->keys_noshift[index]); } } else if (shift && caps_lock) { rv = &(keymap->keys_shiftcapslock[index]); } else if (shift) { rv = &(keymap->keys_shift[index]); } else if (caps_lock) { rv = &(keymap->keys_capslock[index]); } else if (altgr) { rv = &(keymap->keys_altgr[index]); } else { rv = &(keymap->keys_noshift[index]); } return rv; } /*****************************************************************************/ int APP_CC get_keysym_from_scan_code(int device_flags, int scan_code, int* keys, int caps_lock, int num_lock, int scroll_lock, struct xrdp_keymap* keymap) { struct xrdp_key_info* ki; ki = get_key_info_from_scan_code(device_flags, scan_code, keys, caps_lock, num_lock, scroll_lock, keymap); if (ki == 0) { return 0; } return ki->sym; } /*****************************************************************************/ twchar APP_CC get_char_from_scan_code(int device_flags, int scan_code, int* keys, int caps_lock, int num_lock, int scroll_lock, struct xrdp_keymap* keymap) { struct xrdp_key_info* ki; ki = get_key_info_from_scan_code(device_flags, scan_code, keys, caps_lock, num_lock, scroll_lock, keymap); if (ki == 0) { return 0; } return (twchar)(ki->chr); } /*****************************************************************************/ static int APP_CC km_read_section(int fd, const char* section_name, struct xrdp_key_info* keymap) { struct list* names; struct list* values; int index; int code; int pos1; char* name; char* value; names = list_create(); names->auto_free = 1; values = list_create(); values->auto_free = 1; if (file_read_section(fd, section_name, names, values) == 0) { for (index = names->count - 1; index >= 0; index--) { name = (char*)list_get_item(names, index); value = (char*)list_get_item(values, index); if ((name != 0) && (value != 0)) { if (g_strncasecmp(name, "key", 3) == 0) { code = g_atoi(name + 3); } else { code = g_atoi(name); } if ((code >= 0) && (code < 256)) { pos1 = g_pos(value, ":"); if (pos1 >= 0) { keymap[code].chr = g_atoi(value + pos1 + 1); } keymap[code].sym = g_atoi(value); } } } } list_delete(names); list_delete(values); return 0; } /*****************************************************************************/ int APP_CC get_keymaps(int keylayout, struct xrdp_keymap* keymap) { int fd; char* filename; struct xrdp_keymap* lkeymap; filename = (char*)g_malloc(256, 0); /* check if there is a keymap file */ g_snprintf(filename, 255, "%s/km-%4.4x.ini", XRDP_CFG_PATH, keylayout); /* if the file does not exist, try again with 'en-us' as fallback */ if (!g_file_exist(filename)) { g_snprintf(filename, 255, "%s/km-0409.ini", XRDP_CFG_PATH); } if (g_file_exist(filename)) { fd = g_file_open(filename); if (fd > 0) { lkeymap = (struct xrdp_keymap*)g_malloc(sizeof(struct xrdp_keymap), 0); /* make a copy of the build in kaymap */ g_memcpy(lkeymap, keymap, sizeof(struct xrdp_keymap)); /* clear the keymaps */ g_memset(keymap, 0, sizeof(struct xrdp_keymap)); /* read the keymaps */ km_read_section(fd, "noshift", keymap->keys_noshift); km_read_section(fd, "shift", keymap->keys_shift); km_read_section(fd, "altgr", keymap->keys_altgr); km_read_section(fd, "capslock", keymap->keys_capslock); km_read_section(fd, "shiftcapslock", keymap->keys_shiftcapslock); if (g_memcmp(lkeymap, keymap, sizeof(struct xrdp_keymap)) != 0) { g_writeln("local keymap file for 0x%4.4x found and dosen't match " "built in keymap, using local keymap file", keylayout); } g_free(lkeymap); g_file_close(fd); } } g_free(filename); return 0; } xrdp-0.6.0/xrdp/rdp-scan-codes.txt000066400000000000000000000117451203155130500170150ustar00rootroot00000000000000 complete rdp key code listing en-us 4000s in the down flags columm is from repeating keys(holding a key down) When holding a key down, the down flags repeat but the up flags only come once at the end. Rdesktop does not do this as of yet. It always sends down and up for each repeat. key rdp code down flags up flags esc 0x01 1 0000 8000 1 0x02 2 0000 8000 2 0x03 3 0000 8000 3 0x04 4 0000 8000 4 0x05 5 0000 8000 5 0x06 6 0000 8000 6 0x07 7 0000 8000 7 0x08 8 0000 8000 8 0x09 9 0000 8000 9 0x0a 10 0000 8000 0 0x0b 11 0000 8000 - 0x0c 12 0000 8000 = 0x0d 13 0000 8000 backspace 0x0e 14 0000 8000 tab 0x0f 15 0000 8000 q 0x10 16 0000 8000 w 0x11 17 0000 8000 e 0x12 18 0000 8000 r 0x13 19 0000 8000 t 0x14 20 0000 8000 y 0x15 21 0000 8000 u 0x16 22 0000 8000 i 0x17 23 0000 8000 o 0x18 24 0000 8000 p 0x19 25 0000 8000 [ 0x1a 26 0000 8000 ] 0x1b 27 0000 8000 enter 0x1c 28 0000 8000 left ctrl 0x1d 29 0000/4000 c000 right ctrl 0x1d 29 0100/4100 c100 a 0x1e 30 0000 8000 s 0x1f 31 0000 8000 d 0x20 32 0000 8000 f 0x21 33 0000 8000 g 0x22 34 0000 8000 h 0x23 35 0000 8000 j 0x24 36 0000 8000 k 0x25 37 0000 8000 l 0x26 38 0000 8000 ; 0x27 39 0000 8000 ' 0x28 40 0000 8000 ` 0x29 41 0000 8000 left shift 0x2a 42 0000/4000 c000 \ 0x2b 43 0000 8000 z 0x2c 44 0000 8000 x 0x2d 45 0000 8000 c 0x2e 46 0000 8000 v 0x2f 47 0000 8000 b 0x30 48 0000 8000 n 0x31 49 0000 8000 m 0x32 50 0000 8000 , 0x33 51 0000 8000 . 0x34 52 0000 8000 / 0x35 53 0000 8000 right shift 0x36 54 0000/4000 c000 *(keypad) 0x37 55 0000 8000 print scrn 0x37 55 0100 8100 left alt 0x38 56 0000/4000 c000 right alt 0x38 56 0100/4100 c100 space 0x39 57 0000 8000 caps lock 0x3a 58 0000/4000 c000 f1 0x3b 59 0000 8000 f2 0x3c 60 0000 8000 f3 0x3d 61 0000 8000 f4 0x3e 62 0000 8000 f5 0x3f 63 0000 8000 f6 0x40 64 0000 8000 f7 0x41 65 0000 8000 f8 0x42 66 0000 8000 f9 0x43 67 0000 8000 f10 0x44 68 0000 8000 num lock 0x45 69 0000/4000 c000 scroll lock 0x46 70 0000/4000 c000 7(keypad) 0x47 71 0000 8000 home 0x47 71 0100 8100 8(keypad) 0x48 72 0000 8000 up arrow 0x48 72 0100 8100 9(kaypad) 0x49 73 0000 8000 pg up 0x49 73 0100 8100 -(keypad) 0x4a 74 0000 8000 4(keypad) 0x4b 75 0000 8000 left arrow 0x4b 75 0100 8100 5(keypad) 0x4c 76 0000 8000 6(keypad) 0x4d 77 0000 8000 right arrow 0x4d 77 0100 8100 +(keypad) 0x4e 78 0000 8000 1(keypad) 0x4f 79 0000 8000 end 0x4f 79 0100 8100 2(keypad) 0x50 80 0000 8000 down arrow 0x50 80 0100 8100 3(keypad) 0x51 81 0000 8000 pg down 0x51 81 0100 8100 o(keypad) 0x52 82 0000 8000 insert 0x52 82 0100 8100 .(keypad) 0x53 83 0000 8000 delete 0x53 83 0100 8100 ? 0x54 84 ? 0x55 85 ? 0x56 86 f11 0x57 87 0000 8000 f12 0x58 88 0000 8000 ? 0x59 89 ? 0x5a 90 left win 0x5b 91 0100 8100 right win 0x5c 92 0100 8100 menu key 0x5d 93 0100 8100 pause break 0x1d 29 0200 8200 0x45 69 0000 8000 This is a special key that sends 2 down and 2 up like this down 001d 0200 down 0045 0000 up 001d 8200 up 0045 8000 xrdp-0.6.0/xrdp/rsakeys.ini000066400000000000000000000017731203155130500156340ustar00rootroot00000000000000[keys] pub_exp=0x01,0x00,0x01,0x00 pub_mod=0x67,0xab,0x0e,0x6a,0x9f,0xd6,0x2b,0xa3,0x32,0x2f,0x41,0xd1,0xce,0xee,0x61,0xc3,0x76,0x0b,0x26,0x11,0x70,0x48,0x8a,0x8d,0x23,0x81,0x95,0xa0,0x39,0xf7,0x5b,0xaa,0x3e,0xf1,0xed,0xb8,0xc4,0xee,0xce,0x5f,0x6a,0xf5,0x43,0xce,0x5f,0x60,0xca,0x6c,0x06,0x75,0xae,0xc0,0xd6,0xa4,0x0c,0x92,0xa4,0xc6,0x75,0xea,0x64,0xb2,0x50,0x5b pub_sig=0x6a,0x41,0xb1,0x43,0xcf,0x47,0x6f,0xf1,0xe6,0xcc,0xa1,0x72,0x97,0xd9,0xe1,0x85,0x15,0xb3,0xc2,0x39,0xa0,0xa6,0x26,0x1a,0xb6,0x49,0x01,0xfa,0xa6,0xda,0x60,0xd7,0x45,0xf7,0x2c,0xee,0xe4,0x8e,0x64,0x2e,0x37,0x49,0xf0,0x4c,0x94,0x6f,0x08,0xf5,0x63,0x4c,0x56,0x29,0x55,0x5a,0x63,0x41,0x2c,0x20,0x65,0x95,0x99,0xb1,0x15,0x7c pri_exp=0x41,0x93,0x05,0xB1,0xF4,0x38,0xFC,0x47,0x88,0xC4,0x7F,0x83,0x8C,0xEC,0x90,0xDA,0x0C,0x8A,0xB5,0xAE,0x61,0x32,0x72,0xF5,0x2B,0xD1,0x7B,0x5F,0x44,0xC0,0x7C,0xBD,0x8A,0x35,0xFA,0xAE,0x30,0xF6,0xC4,0x6B,0x55,0xA7,0x65,0xEF,0xF4,0xB2,0xAB,0x18,0x4E,0xAA,0xE6,0xDC,0x71,0x17,0x3B,0x4C,0xC2,0x15,0x4C,0xF7,0x81,0xBB,0xF0,0x03 xrdp-0.6.0/xrdp/sans-10.fv1000077500000000000000000024070141203155130500152550ustar00rootroot00000000000000FNT1DejaVu Sans ñÿñÿ€€€€€€€€ñÿ     ñÿ €$ÿ$$hñÿ|’p’| ñÿ `€‘’’dÀ  À ñÿ 8D@ P€ˆ€…Ã|€ñÿ€€€€ñÿ`@@€€€€€€@@ ñÿ€@@ @@€ñÿ’|8Ö ñÿ ÿ€ñÿ@@€ñÿàñÿ€€ñÿ `@@@€€ñÿxH„„„„„Hxñÿà øñÿxŒ @üñÿx„8„xñÿ((HHˆüñÿø€€ø Œxñÿ8D€¸Ì„„Lxñÿü @ñÿx„„„x„„„xñÿxÈ„„Ìtˆpñÿ€€€€ñÿ@@@@€ñÿ p€pñÿ ÿÿñÿ €pp€ñÿpˆ ñÿ  À@@ ‘ ‘ ‘@€@ € ñÿ ""AA€€ñÿ ü‚‚‚ü‚‚‚üñÿ A€€‡A>ñÿ ÿñÿ€€€€€€€€€ñÿÿÿ Àñÿ„ˆ À ˆ„ñÿ€€€€€€€€ü ñÿ Á€Á€¢€¢€”€”€ˆ€€€€€ñÿ ÁÁ¡‘™‰…ƒƒñÿ cÝ€ € € €Ý€c>ñÿpxˆøøñÿ$lØØl$ñÿ ÿñÿà ñÿ >cÝ€”€˜€˜€Õ€c>ñÿðñÿ`` ñÿ ÿ€ÿ€ñÿð `ðñÿð`ðñÿ@€ñÿ„„„„„„þ€€€ñÿ|ôôôtñÿ€€ñÿ@ àñÿÀ@@@àñÿpˆˆˆpøñÿØllØ ñÿ Á€ABBä`  ð0 ñÿ Á€ABBåà @À1à ñÿ ñ€bô`  ð0 ñÿ @€ˆp ñÿ ""AA€€ ñÿ ""AA€€ ñÿ ""AA€€ ñÿ ""AA€€ ñÿ ""AA€€ ñÿ ">AA€€ ñÿ ð #ð>BBƒðñÿ ""AA€€ñÿxx„|„Œt ñÿ ""AA€€ñÿH0x„|„Œt ñÿ ""AA€€€ñÿx„|„Œt ñÿ A€€‡A>ñÿ0H|Ì„„„Ì|L8ñÿ $>A€€‡A>ñÿH0|Ì„„„Ì|L8ñÿ >A€€‡A>ñÿ |Ì„„„Ì|L8ñÿ >A€€‡A>ñÿ |Ì„„„Ì|L8ñÿ $ÿñÿÿÿpØ .1!!!!! ñÿ @€@€ÿÀ@€€@€@€@€@€ñÿ @@ð@\bBBBBBñÿÿÿè¸ ñÿÿÿè¸ ñÿÿÿø ñÿÿÿø ñÿÿÿˆp ñÿÿÿˆp ñÿ€€€€€€€€€€€Àñÿ€€€€€€€€€€Àñÿ€€€€€€€€€€ñÿ€€€€€€€ñÿˆˆˆˆˆˆˆˆˆ0ñÿˆˆˆˆˆˆˆˆñÿÿÿpØ ÀñÿÿÿpØ `ñÿ„ˆ À ˆ„ñÿ€€€€ˆ À ˆñÿˆ À ˆñÿ @€€€€€€€€üñÿ€€€€€€€€€€€€ñÿ€€€€€€€€ü ñÿ@@@@@@@@@@@€€ñÿ€€€€€€üñÿ€€€€€€€€€ñÿ€€€ˆˆ€€€üñÿ€€€€€  €€€€ñÿ@@@p@À@@~ñÿ@@@@`@À@@@@ñÿ ÁÁ¡‘™‰…ƒƒñÿ ¸Ä„„„„„ñÿ ÁÁ¡‘™‰…ƒƒñÿ¸Ä„„„„„ ñÿ $ÁÁ¡‘™‰…ƒƒñÿH0¸Ä„„„„„ñÿ @@®1!!!!!ñÿ Á¡‘™‰…ƒñÿ¸Ä„„„„„8ñÿ <B€€€€€B<ñÿ xÈ€€€Èp ñÿ ~C@€@€ð€@€@€C~ ñÿþÿ €ÐÀ     À€ñÿ >~‚‚‚~ñÿ||Ì„„„Ì|ñÿxÌ„„„„hxñÿüüüñÿ > Àñÿÿÿ x À ñÿ À?A€€‡A>ñÿBB$$$$ ñÿ €€€€¸ÀÄ`„ „ „ „`ƒ€ñÿ€€€€€€€€`ñÿ@@@@ð@@@@ñÿ †‘ à°˜„‚ñÿ`€€€ˆ À ˆñÿ@@@@@@à@@@@ñÿ48X<$$FB ñÿ „`„`„`„`„`„`„`Ì`wà ñÿÿÿ 0@0@(@$@&@"@!@ À À Àñÿ¸Ä„„„„„ñÿ @ñÿ ~‹‰‰‰Éy ñÿþÿÑ€€€€ñÿp€€€¸Ì„„„Ìø€€€ñÿ ÀøÌÄÄÌøÄÆñÿ8fx@À@~ñÿpˆp€ˆpñÿüÀ`0 @Àüñÿþÿp|ñÿ@@ø@@@@@80ñÿ~ñÿ0@@@ð@@@@@pñÿþ ñÿ @ÀÃ<ñÿ‡„„„„Œtñÿ çBBB<ñÿ €†‚†| ñÿ ÀD@(@( ñÿ ‡D€H(00 `Àñÿ ÿ ~0 @ÿñÿøx`Àøñÿ ü 0<üñÿ þ@ ð€€€üñÿü@ 0pÀ€€Ä8ñÿø p€ˆxñÿpØ ü0`Àüñÿ üÀÀÀü‚‚üñÿø€€€ø ˜ðñÿ@@ð`0ðñÿ¼Ä†„Œ˜ À€€ñÿ€€€€€€€€€€€€€€ñÿñÿ ø ø ñÿ€€€€€€€€ñÿ ü€†† ü€ñÿ(ü†| †@ü| ñÿP |øÌ„„ „@Ì€|øñÿ ýñÿ €€ýñÿ€ €€        ` ñÿ Á@Á@¡@‘@™@‰@…@ƒ@ƒ@@@€ ñÿ @ÁÁ¡@‘@™@‰@…@ƒ@ƒ@@@Àñÿ ¹Å…………… ñÿ ""AA€€ñÿH0x„|„ŒtñÿÿÿP ñÿÿÿP ñÿ $BBƒð ñÿ {À†` à„Š qÀ ñÿ >A€€‡‡€A>ñÿ|Ì„„„Ì|þD8ñÿ  >A€€‡A>ñÿ`|Ì„„„Ì|L8ñÿ$„ˆ À ˆ„ñÿÿÿØp "$(0($"ñÿ A€€‡A>ñÿ @|Ì„„„Ì|L8 ñÿÿ€ðñÿ þÂÂÆÄØðÀÀÀÀÀñÿ ÁÁ¡‘™‰…ƒƒñÿ¸Ä„„„„„ ñÿ ">AA€€ñÿ2LH0x„|„Œt ñÿ ð #ð>BBƒð ñÿ {À†` à„Š qÀñÿ =B…‰‰‘¡B¼ñÿ @|Ì”¤¤Ìø ñÿ (""AA€€ñÿP(x„|„Œt ñÿ ""AA€€ñÿpx„|„ŒtñÿP(ü€€€ü€€€üñÿ(xÌ„ü€Ä8ñÿ$ü€€€ü€€€üñÿ8xÌ„ü€Ä8ñÿÿÿ P ñÿ P€€€€€€€ñÿ`@@@@@@@@@ñÿà@@@@@@@ñÿ (dHP``|ñÿ@@@@à@@@~ ñÿÿÿ€€  ,Lñÿø€€pð  ñÿø @€À`0ñÿü< ñÿðp@@ñÿ ~AAA~AñA~ ñÿ @€@€@€@€ÿÀ@€@€a€? ñÿ ""cAA€€ñÿüÈÈüÐÐààü@ñÿx””ü à|@ñÿÿÿ p Àñÿ@@@@à@@@@@À ñÿ =CC=ÀÀñÿ|Ì„„„Ì|ñÿ|BBBüDBBAñÿX`@à@@@ñÿBÿ$ñÿBFdÿ(0`ñÿ¸Ä„ø€„xñÿ|Ì„„„Ì|ñÿøÌ„„„Ìøñÿp€€€øÌ„„„ÌøñÿððñÿpÈ€€¸èx@ñÿ|Ì„„„Ì|ñÿ |Ì„„„Ì|ñÿxÌ„üŒxñÿxŒü„Ìx ñÿ x 5Ä€Œxñÿx€€p€€xñÿpˆpˆp ñÿ p q€ˆpñÿ ñÿø„„ø„„øñÿ x„‚r‚„x ñÿ €<D€Œ„Ä|ñÿ „„„ü„„„ñÿþÿøàñÿ D$ 4Dñÿ€€€€€€ø ñÿ €|Ì„„„Ì|ñÿp˜0 p ñÿpÈ€€€À` p ñÿ ðŒ „@„€…€wð ñÿðŒ „@„€„àŒ0t0À ñÿ ðŒ „@„€…àÐwà€ ñÿ @@ÿÀDDC€@@@@?ÀñÿDDüDDDDD<  ñÿ @@ÿ€LHHIN€?€ ñÿ 8 `ÿÀl@l@l@l@l@l@@@€ñÿ€€€¼à༆‚üñÿ €€€þ„Œ˜° þñÿ”tlH´thñÿü„„ü„„ñÿÀ@`bbbbb"> ñÿ À@`bbbbb">€ñÿ€€ðñÿÀ€àñÿ@@@@@@Àñÿà€€€ñÿ àñÿ à ñÿà àñÿ”tlHñÿP` @ñÿÀÀ€ñÿðð ñÿ@€€ñÿ@@€ñÿÀ@@ñÿ€€€ñÿ€€€ñÿÀ @@@ñÿ`€€@@@ñÿ À€`ñÿÀ`€ñÿ`PñÿP` ñÿ`ñÿ`ñÿ€€€€ñÿðñÿ`@ñÿ@ ñÿ€€€€ñÿðñÿ@ ñÿ @ñÿà@@àñÿà@ñÿ€€€ñÿ€€€ñÿ@@àñÿà@@ñÿ ð ñÿàñÿ`ñÿ€ñÿ``ñÿ€€ÀñÿаñÿP ñÿ à 0ñÿÀàñÿ @` àñÿ€€€€€€ñÿÀÀ àñÿ ``ñÿ`€€@@@ñÿðñÿðñÿðñÿðñÿðñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿ`Pñÿððñÿ  ñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿ`ñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿð€ñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿÀÀ€ñÿ@ÀÀñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿ€€ñÿððñÿpÈ€  ÈpñÿðHHðñÿ@@@@€ñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿ@€ñÿ@€  ñÿ @ˆ""AA€€ñÿ€€ ñÿÿÿ @Ÿ€€€ ñÿ @ @ @ @ @?À @ @ @ @ñÿ@  ñÿþ‚‚‚‚‚‚‚‚‚þ ñÿ @ž!@€@€@€@€@€!ñÿþ‚‚‚‚‚‚‚‚‚þ ñÿÿÿ @ˆ @@€€ ñÿÿÿ @€ @ @ @ @€€9Àñÿ@€ €€€€€€` ñÿ ""AA€€ñÿ ü‚‚‚ü‚‚‚üñÿü€€€€€€€€ ñÿ ""cAAÿ€ñÿü€€€ü€€€üñÿ ÿ @ÿñÿ ÿñÿ Iˆ€ˆ€ˆ€I>ñÿÃB$$Bà ñÿ ˆ€ˆ€ˆ€ˆ€É€k>ñÿ ñÿxŒ„„„Ìx000ñÿ~@€€€€€@x ñÿ|À€€€Àpñÿø€€€ø€€€€ñÿÿÿ 0 Àñÿ À`BLtÄñÿ @@|ü ñÿ 8æ!#€&€$€€€€€€ñÿÀ0(T¤ ñÿ @€ÀÀ€@Œ@Œ@Œ@Œ@ÿÀs€€ ñÿ Á€€€ˆ€ˆ€Ý€w ñÿ cÃÃG{ñÿ d„„„„Ä| ñÿ ÀÀþãÁÁ€Á€Áà ñÿ>FN2üñÿ >c ``? ñÿx„0`€D8ñÿ Ã$<<$Bÿñÿç4<&ÿñÿ |À¼Æ‚‚‚Æ|ñÿp€øŒ„„„ŒxñÿÿÛñÿþ’ñÿ Æ,(8HÈŽñÿ|D„†„ĸÀ`<ñÿpÈ€€€Èpñÿ@@@@@@@@@@À ñÿ fÃÿÿÁC>ñÿxÀ€ø€Àxñÿø ü ðñÿ€øŒ„„Œø€€ñÿ€€€€øÌ„„„Ìø€€€ñÿ A€€þ€€A>ñÿ |€À|†|ñÿ€€€€€€€€€ñÿ @@@@@@@@@ñÿÿÿ À ñÿ?!!!!ð!!Að ñÿ‚‚‚‚ÿà‚‚‚ƒà ñÿ þ€€€€€ñÿ ‚„ˆ°øÈ„‚ƒñÿ ƒƒ…‰™‘¡ÁÁñÿ$‚DD,(8`ñÿ ‚‚‚‚‚‚‚‚þ ñÿ ""AA€€ñÿ ü€€€ü‚‚‚üñÿ ü‚‚‚ü‚‚‚üñÿü€€€€€€€€ ñÿ ?!!!!!!Aÿ€€€€€ñÿü€€€ü€€€ü ñÿÂb02`ÀÀ' " BÂñÿ |‚†xñÿ ƒƒ…‰™‘¡ÁÁñÿ $ƒƒ…‰™‘¡ÁÁñÿ ‚„ˆ°øÈ„‚ƒñÿ ?!!!!!!A ñÿ Á€Á€¢€¢€”€”€ˆ€€€€€ñÿ ÿñÿ Iˆ€ˆ€ˆ€I>ñÿÃB$$BÃñÿ ‚‚‚‚‚‚‚‚ÿñÿ ‚‚‚‚~ ñÿ „ „ „ „ „ „ „ „ ÿà ñÿ„ „ „ „ „ „ „ „ ÿð ñÿ à ? € € €? ñÿ €€€€€€€€ü€‚€‚€‚€ü€ñÿ €€€€ü‚‚‚üñÿ |‚‚| ñÿ‡Àˆ ðˆ ‡Àñÿ ~‚‚‚~"bB‚ñÿx„|„Œtñÿ8@€€øÌ„„„Ìxñÿø„„ø„„øñÿø€€€€€€ñÿ >""""BÿñÿxÌ„ü€Ä8 ñÿ D@$€?€$€D@Ä`ñÿpˆpˆpñÿŒŒ”´¤ÄÄñÿH0ŒŒ”´¤ÄÄñÿˆ ðˆŒñÿ>""""BÂñÿ ÆÆªªª’‚ñÿ„„„ü„„„ñÿxÌ„„„Ìxñÿü„„„„„„ñÿøÌ„„„Ìø€€€ñÿpÈ€€€Èpñÿ þñÿ‚DD(( À ñÿ É€ˆ€ˆ€ˆ€É€ñÿ‚D((D‚ñÿ „„„„„„þñÿ„„„| ñÿ ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ÿ€ ñÿ ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ÿÀ@@ ñÿ ð€€ñÿ ù……ùñÿ€€€ø„„øñÿp˜x˜p ñÿ ™€€ð€€™€ñÿ|„„|dD„ñÿ xÌ„ü€Ä8ñÿ(xÌ„ü€Ä8ñÿ```ü`|bbbbñÿ ø€€€€€€ñÿpÈ€ø€Èpñÿpˆ€pˆpñÿ€€€€€€€€ñÿ @@@@@@@ñÿ@@@@@@@@@@À ñÿ >""#À" B ÃÀ ñÿ „„„ÿ€„@„@‡€ñÿ@@@ø@@\bBBBñÿ ˆ ðˆŒñÿ ŒŒ”´¤ÄÄñÿ$‚DD(( Àñÿ ‚‚‚‚‚‚þ ñÿ @€ÀÀ€@Œ@Œ@Œ@Œ@ÿÀs€ ñÿ A€€€€ˆ€ˆ€”€w ñÿ ü€€€€ñÿ ø >!!> ñÿ €Î`È Øÿ€ÐÐØÌ ÇÀñÿ °þ° ñÿ  ?€?Àd@D`Ä ñÿ 1/D€DÀñÿÁ€ÃÀÂ@þ`ÇàÏðÉوш ñÿ ƒ‡„€øÀ@“ ³ ñÿ b&4<zÙ™™ñÿüHx0ü´´ ñÿ ÏàÌ@ÄÀþ€Ç€Í@Ù Ñ Ñ0 ñÿ Ÿ€™‹þ”€”€ñÿHPpÜ8 ø€øtñÿP`øpð€°@ ñÿ Ì`L€L€m€-- ñÿ D`D€d€%€%5 ñÿ fÃÿÿÁC>ñÿxŒ„ü„Œx ñÿ ÀÁÀAc""6ñÿ CFd$,8 ñÿ ÀÁÀAc""6ñÿ  CFd$,8 ñÿ 0XˆŽ @ÀŒÀÈ€p€ ñÿ t@žÀЀЀ‰€™s ñÿ €@À€@€`€`€`À@dÀñÿ ~ÃÃ~ñÿ€€@À€€€ ‡ ÿøpx ñÿ @ € € € qà ñÿ ?@€ÀÀ€@Œ@Œ@Œ@Œ@ÿÀs€ ñÿ >*A€€€ˆ€ˆ€Ù€wñÿ vÀ€€€€À`>ñÿxÀ€€€Àxñÿ8t0xñÿþ‚‚‚‚‚‚‚‚‚þñÿóÿÀ 8$ `€@<$ àñÿôÿ€1€ à``„ ñÿ $ÆÆÊÊÒÒââÀñÿ H8ŒŒ””¤äÆñÿ `ð`|gaac~ñÿ@@à@@|BB|ñÿüÄÔÌþÀÀÀÀñÿ¼Ä„†„̼„€€ñÿü€€€€€€€€ñÿø€€€€€€ñÿ ? þ ñÿ> ü ñÿüÀÀøÌÆÂ ñÿø€€øˆŒŒ 0ñÿc30`À 0#cC  ñÿ d@4€€&Àd@D ñÿ |‚†x pñÿpˆpˆp pñÿ ÆÌØðèÌÄÂÃñÿˆ ð؈†ñÿ ÆÌØðèìÄÂÃñÿˆ° ðøˆ„ ñÿ cölxtfbaa€ñÿ@ø@DHPxlDB ñÿ ðÀ€€€À` ñÿ ñ€ ñÿ ÃÃÃÿÃÃÃÃÀ€€ñÿ „„„ü„„‡ ñÿ ÃðÃÃÿÃÃÃÃà ñÿ ‡À„„ü„„„ ñÿÿÃÃÃàÃ0ÃÃÃÃ0 ñÿ ü„„‡À„`„`„``@À ñÿ vÀ†‰‰ÉK>€ñÿxÀœ––Ôxñÿ 22"""Ãñÿ ÃÃÃÿÃÃÃàñÿ „„„ü„„„ ñÿ ÃÃÃÿÃÃÃÃÀñÿ „„„ü„„‡ñÿ ††Æ~ñÿŒŒÌ|  ñÿ á€â€â€Ò€Ô€Ô€Ì€À€ÀÀ@€ ñÿ ç§«››ƒ€ñÿ€€€€€€€€€€€ ñÿ ""AA€€ñÿH0x„|„Œt ñÿ ""AA€€ñÿ0x„|„Œt ñÿ ð #ð>BBƒð ñÿ {À†` à„Š qÀñÿH0ü€€€ü€€€üñÿH0xÌ„ü€Ä8ñÿ ñÿxÌ„ü„Ìx ñÿ fÃÿÿÁC>ñÿ(xÌ„ü„Ìxñÿ (|‚‚|ñÿPp˜x˜pñÿ<‚DD,(8`ñÿ<‚DD(( Àñÿ‚DD,(8`ñÿ‚DD(( Àñÿ(‚DD,(8`ñÿ ‚DD(( Àñÿ ‚‚‚‚~ñÿ(„„„|ñÿüÀÀÀÀÀÀÀà ñÿø€€€€€à`` ñÿ €€€€€€€€ü€‚€‚€‚€ü€ñÿ ù……ùñÿ ? þ < 8ñÿ> ü < 0ñÿ c2&cAñÿF$8dB ñÿ c2&cAñÿF$~8dBñÿ >憆Æ~ñÿøˆˆø ñÿ  > æ † † Æ`{À ñÿ €ø€ˆ€Œ€÷€ ñÿ pÜ@8@@@@@À ñÿ ø€p€€€ñÿ pÜ8ñÿøp  ñÿ€€˜˜˜1˜1˜!Àð ñÿ >22 " " " Áà ñÿÿ€ð ñÿ „„„@ü@„@†@ƒÀñÿ sÀ€ÁC>ñÿ |À€„„Äx ñÿ ÿ€€€€€ €ñÿ þñÿ|€€€p€€€|ñÿx€€p€€xñÿ ?#####cC‚ ñÿ>222""Âñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þ ñÿ €B@<@ñÿ >Àþ€€ ñÿ >ÃÁ?À   ñÿ >ÃÀ  ñÿ €€þ‚‚€ÂB|ñÿ0LÄ„„L4 ˜üñÿ €€þ€€€øñÿ >À€€€€þ ñÿ 8fŸ€’@’@ž€€€ ñÿ €Â@‚@‚ÂF<ñÿ €€ü€€€ñÿ€€€€€€€€ø ñÿ €€ù€™€™€™€™€‰ ñÿ €@?ðP0` ` ` `0@À€ñÿ €€‚‚Âf:ñÿ 0`Àþñÿ0LÄ„„L4Løþ ñÿ <ÃÀ ñÿ @þAAAAc? ñÿ ƒÀ‚@‚‚‚‚ÂB|ñÿ 8ÆüƒÂ~ ñÿ €€p  `€ñÿ €þ8`À€‚‚B|ñÿ <Ãñÿ 8f‚ pxñÿ ~Û™ñÿ0LÄ„ÄD$˜ü ñÿ >ÃÀ ñÿ Ã< ñÿ ‚‚Âf:€@@ñÿ |€À|†|ñÿ >À€€€€€ñÿ 8Æ‚Â<ƒÂ~ ñÿ €€ü€€€€ ñÿ >Iˆ€ˆ€ˆ€I> ñÿ 3!€1¿ ÿ! € ñÿ ñÿ0ü @À€À@>ñÿ0ü @À€À@>ñÿ àñÿ@ àñÿÿÿðñÿÿÿðñÿdd‚lƒø‚„xñÿ€@dd‚lƒø‚„xñÿ0l„ƒƒð‚„xñÿ0l„ƒƒð‚„x ñÿ !€&À,@8Àÿ ñÿ $!€&À,@8Àÿñÿ0`€ø`À€€Â~ñÿ@0`€ø`À€€Â~ñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿð ñÿ @à  €à€`ÿÀñÿ  ‡ƒ†Üpñÿ  ƒþñÿ ‚‚Ìxñÿ<$ü€€€€ñÿ ƒƒ‚Æ|ñÿ`ðˆˆðñÿÿÿ$4ðñÿ ƒƒÎ8ñÿ ƒƒÎ8(ñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿ Àñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿ€ñÿ€À@@@@@@ñÿˆÈp@@@@@ñÿV^| ñÿ0@@`À€ÀxñÿpPˆˆˆˆˆpñÿðñÿDD(((8ñÿ8((hDDñÿðøñÿˆ @Hˆñÿ Àñÿ@€€ñÿ øpP ñÿ €@€@ÁÀñÿ  ‡ƒ†Üpñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿÀÀñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þ ñÿ €@€@ÁÀ ñÿ €@€@ÁÀ ñÿ €@€@ÁÀ ñÿ €@€@ÁÀ ñÿ ˆ@€@ÁÀ ñÿ €@€@ÁÀ ñÿ €@€@ÁÀ ñÿ €@€@ÁÀñÿ00@0ü @À€À@>ñÿ0ü @À€À@>ñÿ0ü @À”À@>ñÿ0ü @È€È@>ñÿ(0ü @À€À@>ñÿ0ü @Ô€È@>ñÿ0ü @Ô€Ô@>ñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿÿÿðñÿÿÿ ðñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þ ñÿÿÿ€óñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿÿÿ ðñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þ ñÿ à  €à€`ÿÀñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þ ñÿ @ à  €à€`ÿÀñÿþ‚‚‚‚‚‚‚‚‚þ ñÿ   à  €à€`ÿÀñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þ ñÿ À€€€ÿñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þ ñÿ À À€€€ÿñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿ ‚‚Ìxñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿ ƒƒ‚Æ|ñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿ0ü @Ô€È@>ñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿÿÿ$4ðñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿ ƒƒÎ8ñÿþ‚‚‚‚‚‚‚‚‚þñÿ P`ƒƒÎ8ñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿ`ðˆˆðñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿ€ñÿ€À@@@@@@ñÿˆÈp@@@@@ñÿV^| ñÿ¸àx@@@@@ñÿpPˆˆˆˆ¨Øñÿp@@x0`@ÀñÿDD(((8ñÿ8((hDDñÿðøñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿ ü¤¤ø¤¦¤ü ñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿ ü¢â"â¢âñÿ |â¢â~ññÿþ‚‚‚‚‚‚‚‚‚þñÿ |†ââ‚òòñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿà°ðàñÿü„œ,4ñÿþ‚‚‚‚‚‚‚‚‚þñÿ ~¢Æ8ÆŽúñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿ ââ‚b‚†|ñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿ |‚‚‚â¢âñÿ@ì´„„„ääñÿ þ¡á!9)9ñÿ ÞòR’’’òñÿþ‚‚‚‚‚‚‚‚‚þñÿ â¢â"""Üñÿâ¢Â‚‚†|ñÿâ¢Â‚‚†|ñÿ ÏëÆ’’’þñÿ â¢â’’’üñÿ â¢B’’’þñÿ â¢B’’’þñÿþ‚‚‚‚‚‚‚‚‚þñÿ !!!!!áþñÿ ââ‚b‚†|ñÿ þ‚ð¢|ñÿþ‚‚‚‚‚‚‚‚‚þñÿ~Cs[knñÿþ‚‚‚‚‚‚‚‚‚þñÿx„ääxñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þ ñÿ €g€cs[kn ñÿ ÿ€ü€D€„€„€„€x€ñÿþ‚‚‚‚‚‚‚‚‚þñÿx„„|äøñÿ ûÆ|ââ| ñÿ 0XØÇ€Y#  ñÿâ¢|â¢|ñÿpÈèè ñÿúÿàààÐÐñÿþ‚‚‚‚‚‚‚‚‚þñÿ rN ä䄸ñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿà€€€€ààñÿ ˆˆîîñÿÀà°P( 8(ñÿx„„X0 8(8ñÿÀ@@p0 0(8ñÿþ‚‚‚‚‚‚‚‚‚þñÿ ì´Ä¤ä„|ñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿxÌ„„„Äxñÿü„†ædñÿ0`ÀŒ”ŒÄx ñÿ €€ ####òþñÿ0`ÀœœˆÌ>ñÿø°`ÀœœˆÌ> ñÿ =€ÆâÂ’’’þñÿ þâ"""ââñÿþ‚‚‚‚‚‚‚‚‚þñÿ ò’’’Ò²Þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þ ñÿ ÿ°ü°D°„°„°‡°{à ñÿ ÿ ü D „ „ … {àñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þ ñÿ ÿ€AAc"" ñÿ  ""cAAÿ€ ñÿ ""cAAÿ€ ñÿ ""cAAÿ€ñÿ €à˜††˜à€ñÿ €à˜††˜à€ñÿ (€à˜††˜à€ñÿþ‚‚‚‚‚‚‚‚‚þñÿ €à˜†±†˜à€ñÿ aañÿ aa ñÿ À € €1€Ñ  ñÿ ÿ€AAc"`" ñÿ  Ñ1€ € €À ñÿ ""`cAAÿ€ ñÿ  Ñ1€ € €À ñÿ ""`cAAÿ€ ñÿ ÀÐ À ñÿ €à˜†`†˜à€ ñÿ ÀÐ À ñÿ €à˜†`†˜à€ñÿ ‚à˜††˜à€ ñÿ à Ð  à ñÿ a`a ñÿ  à Ð  à ñÿ a`añÿ aañÿþ‚‚‚‚‚‚‚‚‚þñÿÀñÿ 0PPˆøñÿ0 @€ñÿ€@` ñÿ€  `ñÿ@  €ñÿÀ àñÿ@  `ñÿ(HPPñÿñÿÀñÿàñÿ@@@@ñÿà@@@ñÿÿ AAc"" ñÿ €À"@"cAAÿ€ ñÿ à€˜À†@†˜à€ ñÿ@ 0aa ñÿ €€€€AA"" ñÿ  ""cAA€€ ñÿ ""cAA€€ ñÿ ""cAA€€ñÿ €``€ñÿ €``€ñÿ (€``€ñÿþ‚‚‚‚‚‚‚‚‚þñÿ €`a`€ñÿ `€`ñÿ `€` ñÿ @@@@ € €Ñ  ñÿ €€€€AA"`" ñÿ  Ñ1€ € €@@ ñÿ ""`cAA€€ ñÿ  Ñ1€ € €@@ ñÿ ""`cAA€€ ñÿ  ÀÀ À  ñÿ €```€ ñÿ  ÀÀ À  ñÿ €```€ ñÿ  À Ð À ñÿ `€`` ñÿ  À Ð À ñÿ `€``ñÿ `€`ñÿpÀpñÿ€€€€€ñÿþ‚‚‚‚‚‚‚‚‚þñÿ Ã<ñÿ  <Ãñÿ <Ãñÿ <Ãñÿ üüñÿ üüñÿ üüñÿþ‚‚‚‚‚‚‚‚‚þñÿ üaüñÿ ?@€€€€€@?ñÿ ?@€€€€€@? ñÿ @ @ @ @à@ @ @0À ñÿ ÀÃ< ñÿ 0À @ @à@ @ @ @ @ ñÿ <ÃÀ ñÿ 0À @ @à@ @ @ @ @ ñÿ <ÃÀ ñÿ €@ À @€ ñÿ üÀü ñÿ €@ À @€ ñÿ üÀü ñÿ àÐà ñÿ ?@€€€À€€@? ñÿ àÐà ñÿ ?@€€€À€€@? ñÿ À   Àñÿp€€€p ñÿ @@@@@Ã< ñÿ <@Ã@@@@ ñÿ ü@@@@@ü ñÿ ?@@@€@€@€@€€@?ñÿxÌ„„Ì|ñÿ$xÌ„„Ìø€€€ñÿxÌ„„Ìø€€€ñÿxÌ„„Ìø€€€ñÿ|Ì„„Ìxñÿ|Ì„„Ìxñÿ |Ì„„Ìxñÿ€€€øÌ„„Ìxñÿ€€€€øÌ„„Ìx ñÿ €€€Ù€€€€€ ñÿ xÌ„„Í€|ñÿ 3!!ó> ñÿ xÌ„„Í€ø€€€ñÿ 3!!ó> ñÿ xÌ„„Í€ø€€€ ñÿ €€€€Ù€€€€ ñÿ |Í€„„Ìx ñÿ €€€€Ù€€€€ ñÿ |Í€„„Ìxñÿ >ó!!3 ñÿ €€€øÍ€„„Ìxñÿ >ó!!3 ñÿ €€€€øÍ€„„Ìxñÿ @ÀÀ|fBÂæ<ñÿ€ààñÿ0Ðpñÿ yÍ……Í| ñÿ x€Ì€„€„€Ì€ø€€€ñÿ }Í„„Ìx ñÿ €€€€€€ø€Ì€„„ÌxñÿxÌ„ñÿ$xÌ„€€€€€€ñÿxÌ„€€€€€€ñÿxÌ„€€€€€€ñÿ„Ìxñÿ„Ìxñÿ „Ìxñÿ€€€€€€„Ìxñÿ€€€€€€€„Ìx ñÿ €€€À€€€€€ ñÿ xÌ„€ñÿ 3! à ñÿ xÌ„€€€€€€ñÿ 3! à ñÿ xÌ„€€€€€€ ñÿ €€€€À€€€€ ñÿ €„Ìx ñÿ €€€€À€€€€ ñÿ €„Ìxñÿ à !3 ñÿ €€€€€€„Ìxñÿ à !3 ñÿ €€€€€€€„Ìxñÿ @ÀÀ@@@Âæ<ñÿ€€€àñÿàñÿüñÿ$ü€€€€€€€€ñÿü€€€€€€€€ñÿü€€€€€€€€ñÿüñÿüñÿ üñÿ€€€€€€€€üñÿ€€€€€€€€€üñÿ ?Á ñÿ ü€ñÿ ? à ñÿ ü€€€€€€€€ñÿ ? à ñÿ ü€€€€€€€€ñÿ Á? ñÿ €üñÿ Á? ñÿ €üñÿ à ? ñÿ €€€€€€€€üñÿ à ? ñÿ €€€€€€€€€üñÿ @ÀÀ@@@ÀÀ~ñÿ€€€€àñÿx€€€xñÿ àñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þ ñÿ ÿ€ @@@ À€ ñÿ $$ÀŒ„„Ìx ñÿ ÀŒ„„Ìx ñÿ ÀŒ„„Ìx ñÿ € À@@ Àÿ€ ñÿ € À@@ Àÿ€ ñÿ €€ À@@ Àÿ€ ñÿ xÌ„„ÌÀ ñÿ xÌ„„ÌÀ ñÿðÁˆ˜ð ñÿ ÿ€ p@@ À€ ñÿÙ€€€€ø ñÿ xÍ€„„ÌÀ ñÿÙ€€€€ø ñÿ xÍ€„„ÌÀ ñÿ (xÌ„„ÌÀñÿ`|ñÿpñÿ$$ø ñÿ ÿ€@@@À€ ñÿ $$À€€€À` ñÿ À€€€À` ñÿ À€€€À` ñÿ €À@@Àÿ€ ñÿ €À@@Àÿ€ ñÿ €€À@@Àÿ€ ñÿ `À€€ÀÀ ñÿ `À€€ÀÀ ñÿðÀ0 ñÿ ÿ€p@@À€ ñÿøÐ ñÿ À€0€€À` ñÿøÐ ñÿ À€0€€À` ñÿ0Àð ñÿ €ð@@Àÿ€ ñÿ@0Àð ñÿ €ð@@Àÿ€ ñÿ Øø ñÿ `À0€€ÀÀ ñÿ Øø ñÿ `À0€€ÀÀñÿ@€€|ñÿþ‚‚‚‚‚‚‚‚‚þñÿ ðà>øÀ<ñÿ€€€@`ñÿ à€€€ñÿà€€€ñÿà€€€ñÿ`@€€€ñÿ`@€€€ñÿ `@€€€ñÿ€€€àñÿ€€€€à ñÿ Ì€€€€ñÿ €€€@cñÿ Æ8 ñÿ €à€€€ñÿ Æ8 ñÿ €à€€€ ñÿ €€€€Ìñÿ c@€€€ ñÿ €€€€Ìñÿ c@€€€ñÿ 8Æ ñÿ €€€à€ñÿ 8Æ ñÿ €€€€à€ñÿ @ÀÀp ‚‚ñÿ€à0ñÿ`€€pàñÿ`€€ñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þ ñÿ 0XÈ€ € ñÿ  €€ÈHx ñÿ  €€ÈHx ñÿ xÀL`Ä Æ B`!À ñÿ xÀL`Ä Æ B`!À ñÿ !ÀB`F Ä L`xÀ ñÿ !ÀB`F Ä L`xÀ ñÿ 2 `À ñÿ 0XÈ`€ € ñÿ €` Â2 ñÿ  €€`ÈHx ñÿ €€` Â2 ñÿ  €€`ÈHx ñÿ0Ó11ˆ˜pñÿxÀLlÄ Æ B`!À ñÿ0Ó11ˆ˜pñÿxÀLlÄ Æ B`!À ñÿpИˆ10ñÿ!ÀBlF Ä L`xÀ ñÿpИˆ10ñÿ!ÀBlF Ä L`xÀñÿL–¦äñÿ @ÀüñÿH0@  ü€€€ñÿ@  ü€€€ñÿ@@  ü€€€ñÿüÀ@ ñÿüÀ@ ñÿüÀ@ ñÿ€€€ü  @ñÿ€€€€ü  @ ñÿ Ø€€€€ ñÿ  @Á€üñÿ Ã? ñÿ @  €ü€€€ñÿ Ã? ñÿ @@  €ü€€€ ñÿ €€€€Ø ñÿ üÁ€@  ñÿ €€€€€Ø ñÿ üÁ€@ ñÿ ?à ñÿ €€€ü € @ñÿ ?à ñÿ €€€€ü € @ñÿ @ÀÀ~ˆ ñÿ€ð0 @ñÿþ‚‚‚‚‚‚‚‚‚þñÿ@@@@ñÿ€P `P ñÿ ‡À„„„Ìx ñÿ ø@@@@ À€ ñÿ € À@@@ø@ ñÿ $$xÌ„„„‡À ñÿ xÌ„„„‡À ñÿ xÌ„„„‡Àñÿø  ø€€€ñÿ ø  ø€€€ñÿ€€€ø  øñÿ|À€€À|ñÿ |À€€À|ñÿ|À€€À| ñÿ €Ø€€€€ñÿ |À€€Ã|ñÿp€€pñÿþ‚‚‚‚‚‚‚‚‚þñÿ ðxà|Àñÿ á¢âFDD((ñÿ $((DDFâ¢áñÿ ((DDFâ¢áñÿ ((DDFâ¢áñÿ à¸î`€ñÿ à¸î`€ñÿ wÀÀpñÿ wÀÀp ñÿ à àØÀ ñÿ wÀÀ`pñÿø€pñÿ `ÒÒâ‚‚‚ÂB|ñÿ ŠŠ†‚‚‚ÂB|ñÿ 8f‚‚‚‚â’rñÿ 8f‚‚‚‚ŽŠŽñÿ 8f‚‚‚‚â’rñÿ 8f‚‚‚‚ŽŠŽñÿ ü¢Ãøñÿ ü¢Ãøñÿ ņ€€€À`?ñÿ ņ€€€À`? ñÿ à ÀÐ à ñÿ ņ€€À€À`?ñÿ0Ø€€€xñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þ ñÿ 8lFÂF~À€ ñÿ €€€€€Pp0 ñÿ €€€€€Pp0 ñÿ €€:@fÂÂF| ñÿ €€:@fÂÂF| ñÿ 0PП€€€€ ñÿ 0PП€€€€ñÿ@ÀÐ(D8ñÿ ÿñÿ€P `P ñÿ ÀsÀ†`„ t `À ñÿsÀ†`„ t `À ñÿ€sÀ†`„ t `À ñÿp € € sà`  `À ñÿ@p € € sà`  `À ñÿt„„wÀ`  `À ñÿt„„wÀ`  `À ñÿ t‡„€t€ñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þ ñÿ xÌ„€€ ñÿ €€ÐP00 ñÿ €€„Ìx ñÿ 00PЀ€ñÿ$`xÌz„ €€€€€€ñÿ`xÌz„ €€€€€€ñÿ`xÌz„ €€€€€€ ñÿ ` z   `À ñÿ @` z   `Àñÿ`€€z€ €€€„Ìxñÿ€`€€z€ €€€„Ìxñÿ `z  ñÿb•€”€ÐP ñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þ ñÿ ÀÀ€€€À` ñÿ ÀÀ€€€À` ñÿ €À@@Àÿ€À0 ñÿ €À@@Àÿ€À0 ñÿ `À€€ÀÀÀ ñÿ `À€€ÀÀÀñÿ@€€|ñÿ @Àüñÿ ``ð`ñÿ ``ð`ñÿü€@` ñÿü€@` ñÿ`ð`ñÿ@`ð`ñÿ@à@8 ñÿ€€€øÌ„„Ìøñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿ ü††üñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿ ?aa?ñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿð @€ðñÿðP @Àðñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿ`` ñÿsÀ†`„ t `à ñÿ`ff>&FFñÿFF&>ff>ñÿþñÿŒŒŒŒŒÈxñÿ þþø ñÿ À€@@€@Àñÿþþüþñÿ‚‚DD(( ñÿ ˆ€ˆ€IUU""ñÿø @€øñÿø 0ðñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿø€€€€€€ñÿ((DDD‚ñÿøˆˆˆˆˆˆñÿøˆˆø€€€ñÿ¤¤¤¤ø ñÿ>""""BÂñÿ 0PH¸ˆñÿ0P\°ŽñÿÀ°ðàñÿþ‚‚‚‚‚‚‚‚‚þñÿÀ°ˆˆˆðñÿð€€À€ðñÿà ` àñÿ8D€ŒD8ñÿ€ð€ñÿ€€€€€€ñÿ@@@@@@€ñÿ ÀÀ ñÿ€€€€€ðñÿˆˆØè¨ˆñÿ€Ðа°ñÿ°°ÐЀñÿ0L„„D8ñÿhHxˆxñÿÀ°à€€ñÿÀ°àñÿø ñÿ`ñÿ‰™Zjf$ñÿðp`ñÿðàpñÿp`ñÿ ü~ñÿ€à`ñÿp`ñÿpø€pñÿàðàñÿÀÀ€àñÿ` `Àñÿppðñÿ€€€€€ñÿ€ ÀÀ ñÿ þ’’’ñÿðpñÿ``ñÿðàñÿpˆñÿpñÿààñÿ@@@@`ñÿ  Àñÿðpñÿ¤¤ØñÿP` ñÿþ‚‚‚‚‚‚‚‚‚þñÿà  àà€ñÿP` ñÿ0@pˆpñÿx¨¨p ñÿP` `Pñÿ€€€€€ñÿà€€€ñÿ  ÀñÿP` ñÿà  àà€ñÿP` ñÿ0@pˆpñÿx¨¨p ñÿP` `Pñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿ|ÀìƆÄ̸ñÿ€ð€ñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿà@@à@@àñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿ€€€€€€€€€à`@€ñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿððñÿp€€pñÿp€°pñÿP Pˆpñÿ`À Àñÿ`@@@@@ñÿ@@@À€ñÿppðñÿ  àñÿ@@@@@ñÿ€€€€ñÿ@@@àñÿ@@@àñÿÿÿ Àñÿ€€€€€€€ñÿ€€€€€€€ñÿ€€€àñÿü¤¤ñÿ¤¤ÜñÿpHHH€ñÿàñÿÐаñÿpˆðpñÿp p¨°p ñÿð@0àÀñÿ`@@@@@€ñÿ@@@@` ñÿðpñÿPˆˆpñÿ   àñÿà  àñÿ PPñÿp @ðñÿp @ðñÿp pðñÿp pðñÿpPˆøPpñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þ ñÿ ""AA€€ñÿx„|„ŒtxHxñÿ ü‚‚‚ü‚‚‚üñÿ€€€€øÌ„„„Ìøñÿ ü‚‚‚ü‚‚‚üñÿ€€€€øÌ„„„Ìø ñÿ ü‚‚‚ü‚‚‚üxñÿ€€€€øÌ„„„Ìøxñÿ A€€‡A>ñÿð|Ì„„„Ì|L8ñÿ ÿñÿ€€€€¸Ä„„„„„ñÿ ÿñÿ€€€€¸Ä„„„„„ ñÿ ÿñÿà@@@\bBBBBB ñÿ @€@€@€@€€@€@€@€@€@ àñÿ@@@@\bBBBBB@ àñÿ ÿH0ñÿ€€€€¸Ä„„„„„`ñÿ@@@@@@@@@ð€ñÿ@@@@@@@@ð€ñÿ €€€€€€€€€ñÿ@€ €€€€€€€ñÿ„ˆ À ˆ„ñÿ@€€€€ˆ À ˆñÿ„ˆ À ˆ„ñÿ€€€€ˆ À ˆ ñÿ„ˆ À ˆ„<ñÿ€€€€ˆ À ˆxñÿ€€€€€€€€ü ñÿ€€€€€€€€€€€€ñÿð@@@@@@@@~ñÿð@@@@@@@@@@@@ñÿ€€€€€€€€üxñÿ@@@@@@@@@@@ðñÿ€€€€€€€€ü0Hñÿ@@@@@@@@@@@` ñÿ Á€Á€¢€¢€”€”€ˆ€€€€€ ñÿ ¹ÀÆ „ „ „ „ „ ñÿ Á€Á€¢€¢€”€”€ˆ€€€€€ ñÿ ¹ÀÆ „ „ „ „ „ ñÿ Á€Á€¢€¢€”€”€ˆ€€€€€ ñÿ ¹ÀÆ „ „ „ „ „ ñÿ ÁÁ¡‘™‰…ƒƒñÿ ¸Ä„„„„„ñÿ ÁÁ¡‘™‰…ƒƒñÿ¸Ä„„„„„ ñÿ ÁÁ¡‘™‰…ƒƒ<ñÿ¸Ä„„„„„xñÿ ÁÁ¡‘™‰…ƒƒ$ñÿ¸Ä„„„„„0Hñÿ  ñÿ@ Pñÿ@€ ñÿ@ ñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þ ñÿ A€€€€ˆ€ˆ€”€w ñÿ A€€€€ˆ€ˆ€”€w ñÿ A€€€€ˆ€ˆ€”€wñÿþ‚‚‚‚‚‚‚‚‚þ ñÿ 4,A€€€€ˆ€ˆ€”€w ñÿ 4,A€€€€ˆ€ˆ€”€w ñÿ @'€@     @€ ñÿ @ž!@€@€@€@€@€! ñÿ @'€@    @@à ñÿÿÿ @€ @ @ @ @€€9Àñÿ ñÿ|PÐÐP<ñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þ ñÿ `x@Àx€É8{HÀ€Àx ñÿ `x@Àx€Éx{H`8xñÿ b      `> ñÿaà’”dàñÿ x    àx? ñÿ @xÀÀ€Á€A`zИˆ˜ð ñÿ@xÀÀ€Á€AzHHHHxñÿ|€€€p€€€|ñÿ |‚‚| ñÿ gÀ””dÀñÿþ‚‚‚‚‚‚‚‚‚þ ñÿ h`H@H@€€€€@p` ñÿ  "-€0€€€€à€ ñÿ 〢€¢€¢€¾€¢€¢€¢€ã€ñÿ >"bBBBFñÿ ~ ~bBBFD„ñÿhˆàñÿ 0þä8 ñÿ  €@€¸€‡ñÿ(0PP``@@ð ñÿ Hÿ€HO€HÀH@H@H@HÀO€ñÿ ðÑÉ©••‹‰‡ ñÿq€qyi0mHeHg0cÃx ñÿ >Až€’€ž€€€A>ñÿ FJqBb¤¨ Àñÿ þ¥¥¦¾   à ñÿ f¥¥¥¥¥¥e6 ñÿ i€H€H€  pÀ ñÿ c½‘‘’ဠñÿ þ¥¥¥¾ª¥¥ã€ ñÿ ü‚‚‚þÀ€‚€†@ñÿ üÌÔÔøìä€ñÿ Ëwá ñÿü'À(@(@.@(@'øñÿ éOII ñÿ ÉIs2"64\H€ñÿ  (HP ÿñÿø x0@x  ˜ðñÿ AA€€ ñÿ ó‘‘€!!þñÿ r˜ À@| ñÿ @€À€À€ÿÀ@?ñÿ8D„˜àˆðñÿ8D@@0@€€„| ñÿ ˆˆðñÿ | ü ñÿ0Ø(`     " â8ñÿpàñÿ €†Ãcu˜ŒÆcá ñÿ ÿñÿxxñÿþñÿ p ðpppppø ñÿ Á €À€€€€€€Á€~ñÿð„DŠ(úŠŸ(‘Ä ñÿ €µ55553€ ñÿ ñ ñÿ ü       à ñÿ ÿ€¢€¢€¢€¢€¢€¢€¢€ã€ ñÿ ÿ€H$ € $HÿÀñÿ 8΃á‚|ñÿüñÿüñÿ<$Bà ñÿ R€¢€¢€¢€¢€¥Âüñÿ }¦ÆÊÊÊüñÿ|¤Ä¼ÀÀøñÿ0P``` `ñÿÿÿ(000PPP`Àñÿþ‚‚‚‚‚‚‚‚‚þ ñÿ y€0€x€L€Gñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿøøñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þ ñÿ Á€ABBåà À 1à ñÿ ñ€"bõà À 1à ñÿ Á€ABCÀå À  1À ñÿ ñ€"cÀõ À  1À ñÿ ñ€bÀõ À  1À ñÿ 1€Q’ûÀ À  1À ñÿ Á€ABBÀå À  0À ñÿ à€áÀå À  0À ñÿ Á€ABBÀå @ À 1À ñÿ ñ€bÀõ @ À 1À ñÿ à€áÀå @ À 1À ñÿ ð!€!BBÀE @ À 1À ñÿÁ€ABBä0ñÿ€€€€€€€€€ñÿñÿ ””””””””” ñÿ     @@ˆ€ˆ€……‚ ñÿ €€€€AA"" ñÿ €À€ÀA@A@"@"@@@@ ñÿ€È€ÈAHAH"H"HHHHñÿ€Ê€ÊAJAJ"J"JJJJ ñÿ °À€‰†††‰€°Àñÿ ÃB$$Bà ñÿ Ã@B@$@@@@$@B@Ã@ ñÿÃHBH$HHHH$HBHÃHñÿ€€€€€€€€üñÿ ñÿ @ÿ€ ñÿ ÿ€€@ñÿ €Àà €€€€€€ñÿ `à  ñÿ ÿ€ ñÿ ÿ€€ñÿ €€€€€€€ À€ñÿ  ` ñÿ €ÿÀ€1`ÿÀ`0 ñÿ rúª""""*€' ñÿ 0`ÿÀ`1€ÿÀ€ ñÿ @ÿ€ÿ€@@ÿ€À` ñÿ "wÿ€ª€"""""" ñÿ ÿ€ÿ€ÿ€€ ñÿ """"""ª€w" ñÿ @ÿ€ÿ€€ ñÿ ÿ€ÿ€€@ ñÿ €„„{ ñÿ ˆ€‰€w ñÿ ÿ€1€o ñÿ €€€ñÿ pØØPPPPPP ñÿ ÿ€€ñÿ PPPPPPØP ñÿ €€€ñÿ pØØPPPØP ñÿ ð È$ ñÿ  $H ñÿ H$ ñÿ  $È ð ñÿ €€ÿ€ ñÿ ÿ€€ÿ ñÿ @Þ€­@ ñÿ ¿€_€ñÿ pø¨ ø ø ñÿ ø ø ¨p ñÿ @ô€€@ñÿ pø¨ ñÿ ·€€ñÿ ¨p ñÿ  ÿ€à°€ ñÿ €€ÿ€€€€ ñÿ ?À@@@@?€ñÿ (D((((((8 ñÿ ÿ€€@€@€ñÿ 8(((((l(ñÿ (D(((888ñÿ (D(((((Ä|ñÿ (Tî((((Ä|ñÿ 8T88888Ô|ñÿ (T(D((((8ñÿ (T(D(((Ä| ñÿ Âÿ€€€€ÿ ñÿ ÿ¼°¸¬†ƒ€ ñÿ À`€0€€€€€€ÿ€ñÿ (D((((l( ñÿ yÿ€I€; ñÿ '/€*€""""ªr ñÿ €ÿ€ÿ€€ÿ€€ ñÿ Dÿ€„D ñÿ ÿ€€ ñÿ Iÿ€‰€K ñÿ Jÿ€ŠJ ñÿ *)ÿ€)€+( ñÿ uÿ€•€W4 ñÿ `€ ñÿ €~€ ñÿ €a@@ € ñÿ ÁA""6ñÿ0HŒ€€€€„ÌxñÿpXh˜˜`ñÿüüüñÿüü$$Dü@ ñÿ ?C„€ˆ€ˆ€€ €A¾ ñÿ 6"cAAÿ€ ñÿ ÿACb"4 ñÿ ?€`@€ÿ€€@`?€ ñÿ ?€bD„ÿ€ˆHx?€ñÿ ~@þ€@> ñÿ þ€€ÿ€€€þ ñÿ þ€€ÿ€€€þ ñÿ üþüñÿððððððñÿ ÿñÿ ÿñÿ ÿ@ 0 0`Àÿñÿ ÿ ñÿ ÿ€ÿ€ÿ€ ñÿ ÿ€ñÿþÿ @Àñÿ€€@@@` ñÿ Ö8|Öñÿ``ñÿ€€ñÿÄH(00ñÿ<<ÄH(00ñÿ &>ÄH(00ñÿ tˆˆT ñÿ f™™™fñÿ €€€€€€€þ ñÿ  0 `ÿ€ ñÿ $b€ ñÿ €tBt€ñÿ€€€€€€€€€€€€€ñÿ 0 à ñÿ             ñÿPPPPPXpÐPPPPPñÿ 00pPHȈŒñÿ „ŒÈHXP00ñÿ øŒ„„„„„ñÿ „„„„„„ˆxñÿ(  Àñÿ -$$$$$$$$$´Ø ñÿ -P$@$@$@$@$@$@$@$@$@µ@Ù€ñÿ( p¨¨¨p  À ñÿ +"&~¥¥¥~$$´È ñÿ +P"À&@à¤P¤P¤Pà$@$@µÀÉ€ñÿ( `°¼(  Àñÿ( p¨¸¨p  Àñÿ( p¨¸¨p  Àñÿ‚‚ñÿ‚‚ñÿ€€€€ñÿ‚‚‚‚ñÿ ÿ ñÿ €ü€€ñÿ ÿ ñÿ y€ ñÿ y€ ñÿ p€ ñÿ q˜€€G ñÿ pHI ñÿ@@@@@À@@ ñÿ  y€ ñÿ ÿ€p€Ï ñÿ }€†ÿ€ ñÿ }€Žÿ€ ñÿ €ß€ÿ€ÿ€ ñÿ €ß€ÿ€ ÿ€ ñÿ &€ßˆÿ€ÿ€ ñÿ qŽqŽ ñÿ }€Žx€ß0 ñÿ 0€ßy€†ÿ€ ñÿ 0€ß}€†p€ ñÿ †}€€ÿ€ÿ€ ñÿ €€ÿ€€€ ñÿ 6ã€ã€6 ñÿ 6ã€ÿ€ñÿ ÿÿñÿ ÿÿñÿ €€ÿÿñÿ ÿÿ€€ ñÿ ¿À€¿À€ ñÿ ÿ@@ÿ@@ ñÿ ÿ€$ÿ€ ñÿ $ÿ€ÿ€ ñÿ ÿ€ÿ€ ñÿ "ÿ€ÿ€ ñÿ "ÿ€ÿ€ ñÿ $ÿ€ÿ€ ñÿ >ÿ€ÿ€ ñÿ ~²nÿ€ÿ€ ñÿ 6***ÿ€ÿ€ ñÿ ÿ€ÿ€ñÿ ÿÿ`@ñÿ ÿÿÿ ñÿ ÿ€ÿ€ÿ€ ñÿ ÿÿÿÿñÿ ààÿñÿ ÀxxÀÿ ñÿ €<à<€ÿ€ÿ€ ñÿ à€ðÿ€ÿ€ ñÿ €<à<€ÿ€ÿ€0 ñÿ à€ðÿ€ÿ€0 ñÿ`9€Æç9Àp ñÿ„ç9Àp`9€Æñÿ```ðp``` ñÿ „€ÿ€°€ ñÿ €€äx€ ñÿ „ä €<à ñÿ €€|ì €ÿ€ ñÿ „ü €<ðÿ€ ñÿ €€xà€€ÿ€‚ ñÿ €ð€<à €ß ñÿ €€|ì €€ÿ€’ ñÿ „ü €<ð0€ÿ ñÿ ððñ€<à ñÿ Àx€yÇxà ñÿ üøù€<ð ñÿ Ä|€yÏxð ñÿ €€ ðx€ ñÿ €`8€0`€ ñÿ €€xøñ€€€ ñÿ €À0€8Ç€¸`€ ñÿ €€xø€€x€ ñÿ €À0€8À€x€ ñÿ €€ ôx€ ñÿ „d8€0` @@ ñÿ €@€€@?€ ñÿ þ€€þ ñÿ €DˆˆH?€ ñÿ þ €€þ0 ñÿ ?€@€€@€€ ñÿ þ€€þÿ ñÿ ?€D„ˆH€€ ñÿ þ€€ þÿ ñÿ ?€@€€@€€ ñÿ þþ€ñÿ „„„¤ô¤ˆxñÿ „„„„¤¤ˆxñÿ „„„¤ô¤ˆxñÿ ÿ€€€€ÿñÿ ÿÿñÿ ÿ€€€€ÿÿñÿ ÿÿÿñÿ ü„„„„„„„ñÿ „„„„„„„ü ñÿ >I‰¾€ˆ€ÉI> ñÿ >A¾€€€ÁA> ñÿ >A·œ€œ€÷A> ñÿ >A‡Œ€˜€ñA> ñÿ >Aˆ€ˆ€ÁA> ñÿ >A¤€¤€ÝA> ñÿ >I«œ€œ€ëI> ñÿ >A½€€€€ùA> ñÿ >A¼€€€ÁA> ñÿ ÿ€ˆ€ˆ€¾€ˆ€ˆ€ˆ€ÿ€ ñÿ ÿ€€€€€¾€€€€€€€ÿ€ ñÿ ÿ€¢€÷€œ€œ€¶€ã€ÿ€ ñÿ ÿ€€€€€ˆ€ˆ€€€€€ÿ€ ñÿ €€€€ÿ€€€€€ ñÿ €€€€ÿ€€€€€ ñÿ ÿ€ ñÿ ÿ€ñÿ€€€€ø€€€€ñÿ€€€ø€ø€€€ ñÿ €€€ÿ€€ÿ€€€€ ñÿ     ¿€     ñÿ  ¨¨¨§€¨¨¨  ñÿ    ¿€ ¿€    ñÿ ‚„„„ÿ€ˆ  ñÿ ‚„„ÿ€ˆÿ€  ñÿ ¡¡¢¢¿€¤¤¨¨ ñÿ ¡¡¢¿€¤¿€¤¨¨ñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þ ñÿ €€€á€á€€€€ ñÿ €ðœƒ€ƒœð€ ñÿ €€€a€á€9€€€ÿ€ ñÿ €àœ‡ƒ€ŒðÀÿ€ ñÿ àà¿à à@@ ñÿ ààÿ à @@ ñÿ €þ€€ ñÿ ã€ñÿà@@@@@@@@ñÿ BFd$,8þñÿ þ8($dDFñÿ þBFd$,(ñÿ €€àˆˆþñÿ  "B‚þ ñÿ 1!€ €@À@@À@€` ñÿ À@@@@À`€ €1  ñÿ >A€€€€€€€€€€€€€€€€€€€€ ñÿ €€€€€€€€€€€€€€€€€€€A>ñÿ00HHˆ„„ˆHP00ñÿ€€ñÿ@ð` ñÿþ‚‚‚‚‚‚‚‚‚þ ñÿ À`àà› Ž Ž ± ààÀ` ñÿ À`àÀ›ŽŽ±€àÀÀ` ñÿ À``à   1 `àÀ` ñÿ À` 1€`ÀÀ` ñÿ `À1€`ÀÀ` ñÿ ß0€ÿ€ñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þ ñÿ €€áq€ ñÿ €àC€G<àñÿ€c9ŒÆ0ç09Îs€€ñÿ„ ç89Îs€c9ŒÆ0 ñÿ €àx€ÿ€€x€8À ñÿ À<€ð€ÿ€€pð€ ñÿ ÿ€ÿ€€xð€ ñÿ ÿ€ÿ€€x€<À ñÿ €€€ãð<€ ñÿ €À`œg€<€`€ ñÿ €€|øñ€€# €@ ñÿ ‚Â4€8×€¸` @ ñÿ ÿ€„Œˆˆÿ€ÿ€ ñÿ ÿ€€ € € €ÿ€ÿ€ ñÿ ÿ€€€€€ÿ€ ÿ€ ñÿ ÿ€€€€€ÿ€ ÿ€ ñÿ €€xà € €ÿ€š ñÿ €ð€<è €ÿ€š ñÿ €€xø€€x€ ñÿ €À0€8À„x€ ñÿ €€€å€í€€€€ ñÿ „øœ“€“¼ð @@ ñÿ €€€e€í€9€€€ÿ€ ñÿ „䜋œðð ÿ@ñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þ ñÿ à ÿà0à ñÿ ?€`@€€€ÿ€€€@€`?€ñÿ ~Bþ‚@> ñÿ ?€`@€ÿ€€@`?€ ñÿ €?€`@€ÿ€€@`?€ñÿ ~~@þ€@> ñÿ ?€`@€ÿ€€@`?€€ ñÿ ?€`@ÿ€€ÿ€@`?€ ñÿ þ€ÿà€ü ñÿ þ€€€€ÿ€€€€€þñÿ ü‚þ‚ü ñÿ ÿ€þ€€ÿ€€€þñÿ þüþü ñÿ ÿ€€€€ÿ€€€€ÿ€ñÿfFŠRb|ñÿ ¸lñÿ0H„„„„üñÿ p؈ñÿ ˆp ñÿ ø p؈ñÿ øø p؈ñÿÀ€À@@À€À@@ñÿà€€€€€€€€€€€ñÿà ñÿ€€€€€€€€€€€àñÿ àñÿ x€€€€ñÿ àñÿ €€€€xñÿ à ñÿ ÿ€€€ñÿü„„„„üñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þ ñÿ 〢€”€ÿ€ÿ€”€¶€ã€ ñÿ €€ÿ€ñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿð€€€ñÿðñÿ€€€ðñÿðñÿ` €€€€€€€€€€€ñÿ àñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þ ñÿ÷x €À@ ñÿøx€øñÿÿø°l˜Æƒ‡€‡€˜Â°dÿø ñÿÿø°h˜Èˆ‡‡ˆ˜È°hÿøñÿÿÿ€Û¶€»v€€€·n€¶Î€€€ƒà€ÿÿ€ñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿÿ€ €„€ H€@0€À0€`H€0„€€ÿ€ ñÿ e€‚€À€À€À€€†€cñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿ€€€€€€`ñÿxÌ„„„̸€€€ ñÿ A€€€€ˆ€ˆ€”€wñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿ r΄„„Ìvñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þ ñÿ áÀ!!?ñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þ ñÿ0ø  øxñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þ ñÿ ?€ @@@€ € @@@@ €€ñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿ `@@@À€€€€ñÿ€€€€€€€€€€€€€ñÿ€€€€À@@@` ñÿ€@@ ñÿ€€€€€€€€€€€€€ñÿ0 @@Àñÿð€€€€€€€€€€€€ñÿ€€€€€€€€€€€€€ñÿ€€€€€€€€€€€€ðñÿðñÿ€€€€€€€€€€€€€ñÿðñÿ 8@À€€€€€€€€€€ñÿ à0ñÿ €€€€€€€€€€À@xñÿ €€€€€€€€€€€€€ñÿ àñÿ €€€€À@x@À€€€€ñÿ àñÿ€€€€€€€€€€€€€ñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þ ñÿ À@@?@@@@@?€ ñÿ ?ÀÿÀÿÀÿÀñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þ ñÿ i€¶€Á€Á€Á€¢€œ€cñÿþ‚‚‚‚‚‚‚‚‚þ ñÿ ?À €@€Aÿñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þ ñÿÿÿ 8à/1!!€!1.ñÿ„„„üñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þ ñÿ 3È€˜€ˆ@ˆ@ˆ@ž€A> ñÿ 3Ü€‚€‚@„@ˆ@ž€A> ñÿ 3Ü€‚€‚@Ž@‚@ž€A> ñÿ 3Ä€Œ€”@”@¾@„€A> ñÿ 3Þ€€œ@‚@‚@ž€A> ñÿ 3΀€œ@²@¢@–€I> ñÿ 3^€‚@†@„@„@ˆ€@€? ñÿ 3Ì€’€’@ž@¢@–€I> ñÿ 3Ì€’€’@ž@‚@œ€A> ñÿ 3Ó€µ€”À”À•@»€A>ñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þ ñÿ ÿÀÿÀÿÀÿÀÿÀÿÀ ñÿ ÿÀ ñÿ ÿÀÿÀÿÀ ñÿ ÿÀÿÀÿÀÿÀÿÀ ñÿ ÿÀÿÀÿÀÿÀÿÀÿÀ ñÿ ÿÀÿÀÿÀÿÀÿÀÿÀÿÀÿÀ ñÿ ÿÀÿÀÿÀÿÀÿÀÿÀÿÀÿÀÿÀÿÀ ñÿ ÿÀÿÀÿÀÿÀÿÀÿÀÿÀÿÀÿÀÿÀÿÀ ñÿ ÿÀÿÀÿÀÿÀÿÀÿÀÿÀÿÀÿÀÿÀÿÀÿÀÿÀ ñÿ ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ñÿ ÿÿÿÿÿÿÿÿÿÿÿÿÿñÿ üüüüüüüüüüüüüñÿ øøøøøøøøøøøøøñÿ ðððððððððððððñÿ ÀÀÀÀÀÀÀÀÀÀÀÀÀñÿ €€€€€€€€€€€€€ñÿ øøøøøøøøøøøøø ñÿ „„0€0€„0€0€„„0€ ñÿ ´€´€K@´€´€K@K@´€K@K@´€´€K@ ñÿ {À{ÀÏ@Ï@ÿÀ{ÀÿÀÏ@Ï@{À{ÀÿÀÏ@ ñÿ ÿÀñÿ €€€€€€€€€€€€€ñÿ øøøøøøñÿ øøøøøøñÿ øøøøøø ñÿ øøøøøøÿÀÿÀÿÀÿÀÿÀÿÀ ñÿ øøøøøøÀÀÀÀÀÀ ñÿ ÿÀÿÀÿÀÿÀÿÀÿÀøøøøøø ñÿ ÿÀÿÀÿÀÿÀÿÀÿÀÀÀÀÀÀÀñÿ øøøøøø ñÿ ÀÀÀÀÀÀøøøøøø ñÿ ÀÀÀÀÀÀÿÀÿÀÿÀÿÀÿÀÿÀ ñÿ ÿÀÿÀÿÀÿÀÿÀÿÀÿÀÿÀÿÀÿÀ ñÿ ÿÀ€@€@€@€@€@€@€@€@ÿÀ ñÿ ÿÀ€@€@€@€@€@€@€@€@€ ñÿ ÿÀ¿À¿À¿À¿À¿À¿À¿À€@ÿÀ ñÿ ÿÀÿÀ€@ÿÀ€@ÿÀ€@ÿÀ€@ÿÀ ñÿ ÿÀ­@­@­@­@­@­@­@­@ÿÀ ñÿ ÿÀÿÀ­@ÿÀ­@ÿÀ­@ÿÀ­@ÿÀ ñÿ ÿÀ”ÀÊ@¥@ÒÀ©@”ÀÊ@¥@ÿÀ ñÿ ÿÀÊ@”À©@Ò@¤ÀÉ@’À¥@ÿÀ ñÿ ÿÀÞÀÞÀ­@ÒÀ­ÀÝÀÚÀ¥@ÿÀñÿ þþþþþþþñÿ þ‚‚‚‚‚þ ñÿ ÿÀÿÀÿÀÿÀÿÀ ñÿ ÿÀ€@€@€@ÿÀñÿøøøøøøøøøøñÿøˆˆˆˆˆˆˆˆø ñÿ ?À?€€ÿ ñÿ ?À €@€Aÿ ñÿ ??€€ÿÀ ñÿ "!A@€€€ÿÀñÿ08x|üñÿ0HH„ü ñÿ ÀðüÿÿÀÿüðÀ ñÿ À°Œƒ€À†˜àñÿÀðüøà€ñÿÀ°Œ˜à€ ñÿ àþÿÀþð€ ñÿ àžÀ†¸À ñÿ ÿÀ€€?? ñÿ ÿÀ@€@€!! ñÿü|x80ñÿü„HH0 ñÿ ÀÀÀ?ÀÿÀ?ÀÀÀÀ ñÿ À@ @0@À@ @@@Àñÿ <ü< ñÿ 4Ä$ ñÿ ÀÀÿÀÀÀ@ ñÿ À@à@@@À ñÿ ?€ÿÀ€? ñÿ !@€€@@€! ñÿ -^€¿@^€- ñÿ >M€¾€¿@ÿ@¿@¾€\€#ñÿ00HHˆ„„ˆHP00 ñÿ >A€€€€@€@€@€€@€# ñÿ A€@€@€@@€ ñÿ >U€Õ€Õ@Õ@Õ@Õ€U€7 ñÿ >A€ˆ€–@¢@’@œ€@€# ñÿ €€ÿÀÿÀÿÀÿÀ€€ ñÿ >y€ø€ø€ø@ø@ø€x€; ñÿ >G€‡€‡€‡À‡À‡€G€' ñÿ >€ÿ€ÿ€ÿÀ€@€€@€# ñÿ >A€€€€€€@ÿÀÿ€€? ñÿ >G€‡€‡€‡À€@€€@€# ñÿ >G€‡€‡€‡ÀÿÀÿ€€? ñÿ8xøøøøøx8ñÿàðøøøøøðà€ñÿ ÿÿÿçÃÃçÿÿÿ ñÿ ÿÀÿÀìÀ¿@¿ÀÿÀÿÀÿÀÿÀ¿@ÎÀóÀÿÀ ñÿ ÿÀÿÀìÀ¿@¿ÀÿÀÀ ñÿ ÀÿÀ¿@ÎÀóÀÿÀñÿ0@€€€ñÿ`ñÿ Àñÿ€€@  ñÿ >A€€€€@@ ñÿ €@€€@€# ñÿ @ÀÀÀÀÀÀ?ÀÀÿÀ ñÿ €Ààðøüþÿÿ€ÿÀ ñÿ ÿ€ÿþüøðàÀ€ ñÿ À?ÀÀÀÀÀÀÀ@ñÿ`à ñÿ ÿÀø@ø@ø@ø@ø@ø@ø@ø@ÿÀ ñÿ ÿÀ‡À‡À‡À‡À‡À‡À‡À‡ÀÿÀ ñÿ ÿÀÿ@þ@ü@ø@ð@à@À@€@ÿÀ ñÿ ÿÀ€ÀÀƒÀ‡ÀÀŸÀ¿ÀÿÀÿÀ ñÿ ÿÀ„@„@„@„@„@„@„@„@ÿÀ ñÿ "-A@€€€ÿÀ ñÿ 99x€x€ÿÀ ñÿ &'GG€‡€ÿÀ ñÿ€0@@ €€€€€€€@ `€ ñÿ ÿÀ„@„@„@ü@€@€@€@€@ÿÀ ñÿ ÿÀ€@€@€@ü@„@„@„@„@ÿÀ ñÿ ÿÀ€@€@€@‡À„@„@„@„@ÿÀ ñÿ ÿÀ„@„@„@‡À€@€@€@€@ÿÀ ñÿ >I€ˆ€ˆ€ø@€@€€@€# ñÿ >A€€€€€ø@ˆ@ˆ€H€+ ñÿ >A€€€€€Àˆ@ˆ€H€+ ñÿ >I€ˆ€ˆ€À€@€€@€# ñÿ ÿ€‚„ˆ À€ ñÿ À @@@@@@À@ ñÿ €À ˆ„‚€€ÿÀ ñÿ ÿ€€€€€€€€€€€€€€€ÿ€ ñÿ ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ñÿ þ‚‚‚‚‚þñÿ þþþþþþþ ñÿ @À@@@@@ @@@ÿÀ ñÿ ).ßÀ#@ ñÿ €?à?àÿà ñÿ ?€ÿÀ ñÿ   €ŽR«€ €! ñÿ `  À ñÿ  ÿ€?2! ñÿ ó€A"">!ñÿ @€@  ñÿ ÿ€€€‚„„‚€€€À ñÿ ?@€€€Œ@Œ@€€€€A> ñÿ Á€€€€À€€ã€’@’@〠ñÿ 〒@²ÀÁ€€À€À€€a€>ñÿ <|„„„Ìx ñÿ à  " ÝÀˆˆˆpñÿ?ðà÷üžd;ð?0;x>ø?øñÿø $”¤k\7°LLGð ñÿ ÿÀ€@€@€@€@€@€@€@ÿÀ ñÿ ÿÀ@‚@„@„@ˆ@˜@@ÿÀ ñÿ ÿÀ¡@²@œ@Œ@–@£@€@ÿÀñÿ€ˆP` Pˆ ñÿ @€@@@ÿ€;@ ñÿ ÷€À€?€ ñÿ a€€€€€€€€€€€€ÿÀ ñÿ ?€€ÿ€ÿ€ÿ€ÿ€ÿÀ ñÿ  i€ÿÀ{€k€ ñÿ €¾€½€}€ ñÿ ÿÀ€€€€€ ñÿ ÿÀüþüøx ñÿ ÿÀ€ €0€€€ñÿ4ôä„„„ü ñÿ ÿÀŽ‚„„|ñÿü„„„ôt ñÿ AA7Ý€ºÀ_ò€Í€ ñÿ ?á0 '€< ñÿ ?c€ó€ÿÀŒ@”€Œ€_> ñÿ "!!?Ö€.@ s€ñÿ þÜ|xTxX00ñÿ 8(™ÿñÿ(ì0ñÿ V<88|Vñÿ pø ñÿ ˆ@ÿÀˆ@ ñÿ >`ÀÁÁ€À€`p ñÿ k©€©@©@©€š€ñÿ üÖÖºÖz8 ñÿ € €€€#€|€@@ ñÿ ?I€ˆ€ˆ@œ@ª€i€i ñÿ €€ð€ø@Û@ø€€ ñÿ ÿÀÿÀÿÀ ñÿ óÀÿÀÿÀ ñÿ ÿÀóÀÿÀ ñÿ óÀóÀÿÀ ñÿ ÿÀÿÀóÀ ñÿ óÀÿÀóÀ ñÿ ÿÀóÀóÀ ñÿ óÀóÀóÀ ñÿ {{T€óÀ^€k{€ ñÿ ?A€’€’@Œ@’€b€a ñÿ ?A€’€’@¢@’€L€a ñÿ ?€Ì€ÿÀÞÀ߀a€ ñÿ ).ÓÀ+@ñÿ p(((0`ñÿ 8` ÀÀ  P8ñÿ„„xH„„„x xñÿ |‚‚Â|<ñÿ <|‚‚Âl ñÿ ÀÀ?@F‚‚‚F<ñÿ zʆ þñÿ €à€°HD„ˆñÿ ÓRR~RRÓ8(ñÿ 8ÒWRV<8ñÿ à˜Œˆø€€€€ø ñÿ @£À’@”@  ñÿ @Á€!6!!!# ñÿ ÿ€"""""">ဠñÿ ?X€ˆˆw€€€‡€~ñÿ ""b’”¤H ñÿ ¶JJÀK@K@J@J@J€J€ ñÿ "!"óÀÿÀ ñÿ [mIIIIIIH€` ñÿ ÀÀ@>@@ @"@€ ñÿ XXh('€€€ ñÿ €’€€’€ñÿ ÃD$$þ$$D‚ ñÿ  6M€ˆ€ˆ€H€?A? ñÿ ok€®€_km3??ñÿ þ‚|DDD|‚þñÿ p0XˆpPPˆüñÿ pHÄ„‚’bB~ñÿ 8$D(V‚ÿ ñÿ  6o€û€û€{€?_? ñÿ /j€ª€[[=#??ñÿ þB|||||‚þñÿ 00Xˆpppxüñÿ P0ø|~î~>ñÿ <<8~þÿÿñÿ 8<~þÿîT ñÿ ÷€ˆ€€€€€@€A"ñÿ 8(D‚‚BD( ñÿ  €ÿ€w€{ñÿ (D‚‚ºT ñÿ w€ÿ€ÿ€€€? ñÿ 8<~þ~< ñÿ >"" €œ€{ ñÿ 8V4,Ë€€€@€?ñÿ ààñÿ,$ ààñÿ &"""""bæ ñÿ € €€ € € € €ã€ã€ñÿ€€€€°Ð Àñÿ€ à  à  ñÿ `  °à€ñÿ ‘~‘ñÿ ç ñÿ >M7•@Á€~€M2 ñÿ "E€Ä€€@û€ ñÿ "E€È€ž@û€ ñÿ "M€Â€œ@û€ ñÿ " U€Þ€„@û€ ñÿ "]€Â€œ@û€ ñÿ "]€Ô€Œ@û€ ñÿ "E€Ä€ˆ@û€ ñÿ "A€À€€@û€ ñÿ 76a€áÀÀ€{€? ñÿ ?i€é€žÀž@¿€H€ ñÿ Ÿ€¶€á@áÀဿ€E> ñÿ €€²€Í@ÉÀµ€‚€A>ñÿ `@@0¼„„Ëx ñÿ ÿ€€€€€ˆ€Œ€€€€€€€ÿ€ ñÿ ÿ€‚€ƒ€€€€€ €°€€€ÿ€ ñÿ ÿ€‚€ƒ€ˆ€Œ€ €°€€€ÿ€ ñÿ ÿ€¢€³€€€€€¢€³€€€ÿ€ ñÿ ÿ€¢€³€ˆ€Œ€¢€³€€€ÿ€ ñÿ ÿ€¢€£€¢€³€€€³€€€ÿ€ ñÿ ?@€€€@ƒ@€€€€A> ñÿ ?@€€€¡@£@€€€€A> ñÿ ?€ÿ€þÀüÀÿ€€ ñÿ ?€ÿ€ÞÀÜÀÿ€€ ñÿ ÿÀ ñÿ óÀ ñÿ ÿÀÿÀ ñÿ óÀÿÀ ñÿ ÿÀóÀ ñÿ óÀóÀñÿ À°Ž‚‚‚ú„€ñÿ Àp~~~~Ž€€ ñÿ sa€ñÀš@ q€ ñÿ  ?ˆ€È€?ñÿ BD(8nv‰ñÿ àà8``8`0 ñÿ  s€b€¢€’€”@”@ó€ ñÿ O‡€€@@ñÿ <$$™v8 ñÿ aÀ€H€ŒÀ@€Asñÿ Þî(ñÿ 8(ÿ¦z­µj8ñÿ Û½üº|(ñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þ ñÿ *)A@€ˆ€ÿÀñÿ 0``€ ñÿ 6I”€”€”€$$>$ ñÿ ÀÀ À?L€L@Œ@L€? ñÿ ÀÀÀ?L€L€Œ@L€€|ñÿ  8L„„Dxxñÿ 8pˆ„„ˆx ñÿ w{ºt>"B"6>ñÿ 8X|8D„„D8 ñÿ 0M€…@‡à…Àxñÿ xÌ„„Ìxñÿ xüüüüxñÿ ``ñÿ |ªª| ñÿ 뀜€œ€¿€H ñÿ qÀ‘ Ž ñÀ ñÿ ~€€~ñÿ pPЈPP ñÿ |‚‚Â|ñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þ ñÿ p0ÏÀô ñÿ €Á€fãÀ ñÿ B¿ÀHp ñÿ `áà~€öÀa@ñÿþ‚‚‚‚‚‚‚‚‚þ ñÿ cœ€€°€ €°€Q> ñÿ c‰˜€ˆ€º€ç€Â€A> ñÿ  Œÿ€Œ ñÿ ÿ€Á€¾€œ€ª€Á€ÿ€ñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿ ðð°ðÐÐаð ñÿ >IÀXÀ°ÀtÀ‹ñÿ pèÔj6  ñÿ ¿€á@ÿ€ñÿ +VªÔèp ñÿ |‹—€ê ñÿ ÿ÷€þñÿ  à@ñÿ  \xp`ñÿ Æl88lÆ‚ ñÿ "w>>÷€cñÿ f,88hÌÀ€ñÿ Çî|x8|þÌ€ ñÿ <,뀈€ÿ€ˆ€o, ñÿ ÿ€ÿ€ÿ€ ñÿ ÿ€÷€ ñÿ ã€ã€ã€ñÿ þþñÿ xÌ‚ÎÎHHH8ñÿ xÖþþÖXXX8 ñÿ >ˆ€É€ÿ€ˆ€ˆ€> ñÿ ïcBcÿ€ ñÿ É€ÿ€ ñÿ É€ÿ€É€ ñÿ ë€ÿ€ë€ ñÿ <Kë€ÿ€k ñÿ > ñÿ "C4ñÿþ‚‚‚‚‚‚‚‚‚þ ñÿ àÀ@€!€!$€{€ ñÿ w÷瀀€Á€Ã€É€]> ñÿ  sÀ!€! ñÿ îÀ^€/€/$€{€ ñÿ  wÀ.€+1 ñÿ  {À%€! ñÿ  À'€+1 ñÿ  áÀ!€#-;0€ ñÿ Yÿ€>ÿ€û€ ñÿ ë€6$wÉ€ ñÿ I*ÿ€*I ñÿ %€5€ ñÿ k^n—€vVy ñÿ I>>É ñÿ J>>*I ñÿ {>ÿ€>~I ñÿ *>>ÿ€¾€* ñÿ ,]¾€ÿ€ß>]* ñÿ Éë€ë€É€ ñÿ Éë€ë€É€ ñÿ ßë€ÿ\ë€û€ ñÿ ×û€ÿ€] ñÿ ÷€ã€Á€Ccv ñÿ $€¾€]Iv ñÿ ß»æ€ã€Õ€¿½^ ñÿ w•Ý€£€¢€ã€Ý€·~ ñÿ ßì€ÿ€T ñÿ >kkª€ ñÿ >kÝ*û€. ñÿ IIÿ€œ€ë€Ë€_ ñÿ Éë€ë€Ë€ ñÿ I*<ë€*I ñÿ ]2Ý€ÿ€,*] ñÿ K*ë€${I ñÿ k*œ€ÿ€<kIñÿþ‚‚‚‚‚‚‚‚‚þ ñÿ <C€€€@€@€@€@€€€€ñÿþ‚‚‚‚‚‚‚‚‚þ ñÿ ÿÀ€@€@€@€@€@€@€@ÿÀÿÀ ñÿ ÿÀ€@€@€@€@€@€@€@€@ÿ€ ñÿ ÿÀ€@€@€@€@€@€@€@ÿÀÿÀ ñÿ ÿÀ€@€@€@€@€@€@€@€@ÿÀñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þ ñÿ ?€÷€oñÿþ‚‚‚‚‚‚‚‚‚þñÿ €€€€€€€€€€€€€ñÿ àààààààààààààñÿ øøøøøøøøøøøøøñÿ@ÀÀÀñÿÀÀ@€ñÿHØØØñÿØØHñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿ ~ôôô|ddLxñÿ pøøø pppñÿ Lîþ|0888 ñÿ ÷€÷€ÿ€ÿ>ñÿ pøü|>üøøpñÿ y™†>~~<2 ñÿ LlÞ€Ÿ€Nñÿ  `ÀÀÀÀÀÀ` ñÿ À 00 Àñÿ 00```àà```00ñÿ ``0000000p``ñÿ 00``ÀÀÀ``00ñÿ À``0000``Àñÿ 8p`ààp88 ñÿ àp08  88pàñÿ 88ppàpp88ñÿ pp8888ppñÿ @€€€€€€€€€@ ñÿ €@@@@@@@@@@@€ñÿ 80000ð0000ñÿ àp0000<000pà ñÿ ?w€÷€÷À÷À÷Àá€> ñÿ ?c€ý€ýÀûÀ÷Àé€> ñÿ ?a€ý€ýÀñÀüÀé€> ñÿ ?{€ó€ëÀëÀÑÀû€> ñÿ ?a€ï€ãÀýÀýÀé€> ñÿ ?c€ß€ÇÀÏÀÏÀK€> ñÿ ?a€ý€ûÀûÀóÀ÷€> ñÿ ?s€í€íÀãÀÍÀé€> ñÿ ?y€|ÀüÀøÀþÀt€?€ ñÿ ?o€ï€ë@ë@ë@Ä€> ñÿ $€\@„ „ „ „ „@_@ € ñÿ ,€S@ ƒ ‚ „ ˆ@_@ € ñÿ .€S@ ‚ ‡ @^@ € ñÿ "€F@Š ’ ’ ¿ ‚@B@ € ñÿ >€P@ ž @^@ € ñÿ &€X@ ž ‘ ‘ ‘@N@ € ñÿ ?€A@‚ ‚ „ „ „@H@ € ñÿ .€Q@‘ š ž ‘ ‘@^@ € ñÿ ,€[@‘ ‘ › … @^@ € ñÿ 3€TÀ” ” ” ” ”À[@ € ñÿ ;€kÀûàûàûàûà{À`À?€ ñÿ 3€lÀþàüàýàûàwÀhÀ?€ ñÿ 1€lÀþàýàüàþà~ÀaÀ?€ ñÿ =€}ÀõàýàíàÐà}À}À?€ ñÿ !€oÀïàáàþàþà~ÀaÀ?€ ñÿ 9€gÀïàñàîàîànÀqÀ?€ ñÿ  €~Àýàýàûàûà{ÀwÀ?€ ñÿ 1€nÀîàåàçàîànÀaÀ?€ ñÿ 3€dÀîàîàäàþà~ÀaÀ?€ ñÿ .€m@ïàë ë ë o@D@?€ ñÿ ÿ€ÿ€ñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿ €À`0 ñÿ ÿ€ó€ñÿ 0`À€ ñÿ  ñÿ ÿ€ÿ€ ñÿ €€ ñÿ ÿ€ÿ€ ñÿ /€/€ ñÿ .¯€¯. ñÿ ÿ€ÿ€ ñÿ @80À ñÿ @8"\  ñÿ @p<??<p@ ñÿ ÿÿ€ÿ€ ñÿ ÿ€ÿ€ƒñÿ ðøøð ñÿ þÿÿü ñÿ û€ú ñÿ ý€€þ ñÿ €€~@@@€Àÿ€ ñÿ ÿ€üÀ@@@@?@€ñÿ 䂃öüñÿ þ‡ƒ‚ô ñÿ ù€€€ÿñÿþ‚‚‚‚‚‚‚‚‚þ ñÿ ý€€€€~ñÿ |ö| ñÿ ñ±€ÿðñÿ 0x8 ñÿ ðy€ñÿ 8x0 ñÿ ðx8 ñÿ ðñ€ÿñÿ 8xð ñÿ ø€÷ ñÿ bù ñÿ ù€y€ñ ñÿ û€}€ú ñÿ x€z ñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿ0(HD„ü„HH00ñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿð          ðñÿðPPPPPPPPPPðñÿ @@@€€@@@ ñÿ€À@@@ @@@€€ñÿ((PPP  PPP((ñÿ ðPPP((PPP  ñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þ ñÿ 6wÕ€Õ€UUUU ñÿ UUUUÕ€U6 ñÿ €@\@8 @@€ ñÿ 6EG@C€Ab> ñÿ%€DÿøDˆD%€ñÿ @ÿÿ€@ ñÿÿÿ€ñÿ0`ÿÿ€`0ñÿÿ€€€ÿñÿÿÿ€€ÿñÿÿ€€€€ÿñÿ€@€ÿÿ€€€@€€ñÿ€€ÿÿ€€€€€ñÿ€ÿ€€€€€ÿ€€ñÿ€ÿÿ€€€€ÿÿ€ñÿW¯€«W€ñÿ ñÿ ÀÀñÿ ÀÀñÿ ÀÀÀÀñÿ ÀÀñÿ ÀÀÀÀñÿ ÀÀÀÀñÿ ÀÀÀÀÀÀñÿ ÀÀñÿ ÌÌñÿ ÀÀñÿ ÌÌÀÀñÿ ÀÀñÿ ÌÌÀÀñÿ ÀÀÀÀñÿ ÌÌÀÀÀÀñÿ ÀÀñÿ ÀÀ ñÿ ÌÌñÿ ÀÀÌÌñÿ ÀÀñÿ ÀÀ ÀÀñÿ ÌÌÀÀñÿ ÀÀÌÌÀÀñÿ ÀÀÀÀñÿ ÌÌ ñÿ ÌÌñÿ ÌÌÌÌñÿ ÀÀñÿ ÌÌ ÀÀñÿ ÌÌÀÀñÿ ÌÌÌÌÀÀñÿ ÀÀñÿ ÀÀ ñÿ ÀÀ ñÿ ÀÀÀÀ ñÿ ÌÌñÿ ÀÀÌÌñÿ ÀÀÌÌñÿ ÀÀÀÀÌÌñÿ ÀÀÀÀñÿ ÌÌ ñÿ ÀÀ ñÿ ÌÌÀÀ ñÿ ÌÌñÿ ÌÌÌÌñÿ ÀÀÌÌñÿ ÌÌÀÀÌÌñÿ ÀÀÀÀñÿ ÀÀ ñÿ ÌÌ ñÿ ÀÀÌÌ ñÿ ÌÌñÿ ÀÀ ÌÌñÿ ÌÌÌÌñÿ ÀÀÌÌÌÌñÿ ÀÀÀÀÀÀñÿ ÌÌ ñÿ ÌÌ ñÿ ÌÌÌÌ ñÿ ÌÌñÿ ÌÌ ÌÌñÿ ÌÌÌÌñÿ ÌÌÌÌÌÌñÿ ÀÀñÿ ÀÀÀÀñÿ ÀÀÀÀñÿ ÀÀÀÀÀÀñÿ ÀÀÀÀñÿ ÀÀÀÀÀÀñÿ ÀÀÀÀÀÀñÿ ÀÀÀÀÀÀÀÀñÿ ÀÀñÿ ÌÌÀÀñÿ ÀÀÀÀñÿ ÌÌÀÀÀÀñÿ ÀÀÀÀñÿ ÌÌÀÀÀÀñÿ ÀÀÀÀÀÀñÿ ÌÌÀÀÀÀÀÀñÿ ÀÀñÿ ÀÀ ÀÀñÿ ÌÌÀÀñÿ ÀÀÌÌÀÀñÿ ÀÀÀÀñÿ ÀÀ ÀÀÀÀñÿ ÌÌÀÀÀÀñÿ ÀÀÌÌÀÀÀÀñÿ ÀÀñÿ ÌÌ ÀÀñÿ ÌÌÀÀñÿ ÌÌÌÌÀÀñÿ ÀÀÀÀñÿ ÌÌ ÀÀÀÀñÿ ÌÌÀÀÀÀñÿ ÌÌÌÌÀÀÀÀñÿ ÀÀñÿ ÀÀ ÀÀñÿ ÀÀ ÀÀñÿ ÀÀÀÀ ÀÀñÿ ÌÌÀÀñÿ ÀÀÌÌÀÀñÿ ÀÀÌÌÀÀñÿ ÀÀÀÀÌÌÀÀñÿ ÀÀñÿ ÌÌ ÀÀñÿ ÀÀ ÀÀñÿ ÌÌÀÀ ÀÀñÿ ÌÌÀÀñÿ ÌÌÌÌÀÀñÿ ÀÀÌÌÀÀñÿ ÌÌÀÀÌÌÀÀñÿ ÀÀñÿ ÀÀ ÀÀñÿ ÌÌ ÀÀñÿ ÀÀÌÌ ÀÀñÿ ÌÌÀÀñÿ ÀÀ ÌÌÀÀñÿ ÌÌÌÌÀÀñÿ ÀÀÌÌÌÌÀÀñÿ ÀÀñÿ ÌÌ ÀÀñÿ ÌÌ ÀÀñÿ ÌÌÌÌ ÀÀñÿ ÌÌÀÀñÿ ÌÌ ÌÌÀÀñÿ ÌÌÌÌÀÀñÿ ÌÌÌÌÌÌÀÀñÿ ÀÀñÿ ÀÀ ñÿ ÀÀ ñÿ ÀÀÀÀ ñÿ ÀÀ ñÿ ÀÀÀÀ ñÿ ÀÀÀÀ ñÿ ÀÀÀÀÀÀ ñÿ ÀÀÀÀñÿ ÌÌ ñÿ ÀÀ ñÿ ÌÌÀÀ ñÿ ÀÀ ñÿ ÌÌÀÀ ñÿ ÀÀÀÀ ñÿ ÌÌÀÀÀÀ ñÿ ÀÀÀÀñÿ ÀÀ ñÿ ÌÌ ñÿ ÀÀÌÌ ñÿ ÀÀ ñÿ ÀÀ ÀÀ ñÿ ÌÌÀÀ ñÿ ÀÀÌÌÀÀ ñÿ ÀÀÀÀÀÀñÿ ÌÌ ñÿ ÌÌ ñÿ ÌÌÌÌ ñÿ ÀÀ ñÿ ÌÌ ÀÀ ñÿ ÌÌÀÀ ñÿ ÌÌÌÌÀÀ ñÿ ÀÀÀÀñÿ ÀÀ ñÿ ÀÀ ñÿ ÀÀÀÀ ñÿ ÌÌ ñÿ ÀÀÌÌ ñÿ ÀÀÌÌ ñÿ ÀÀÀÀÌÌ ñÿ ÀÀÀÀÀÀñÿ ÌÌ ñÿ ÀÀ ñÿ ÌÌÀÀ ñÿ ÌÌ ñÿ ÌÌÌÌ ñÿ ÀÀÌÌ ñÿ ÌÌÀÀÌÌ ñÿ ÀÀÀÀÀÀñÿ ÀÀ ñÿ ÌÌ ñÿ ÀÀÌÌ ñÿ ÌÌ ñÿ ÀÀ ÌÌ ñÿ ÌÌÌÌ ñÿ ÀÀÌÌÌÌ ñÿ ÀÀÀÀÀÀÀÀñÿ ÌÌ ñÿ ÌÌ ñÿ ÌÌÌÌ ñÿ ÌÌ ñÿ ÌÌ ÌÌ ñÿ ÌÌÌÌ ñÿ ÌÌÌÌÌÌ ñÿ ÌÌñÿ ÀÀÌÌñÿ ÀÀÌÌñÿ ÀÀÀÀÌÌñÿ ÀÀÌÌñÿ ÀÀÀÀÌÌñÿ ÀÀÀÀÌÌñÿ ÀÀÀÀÀÀÌÌñÿ ÌÌñÿ ÌÌÌÌñÿ ÀÀÌÌñÿ ÌÌÀÀÌÌñÿ ÀÀÌÌñÿ ÌÌÀÀÌÌñÿ ÀÀÀÀÌÌñÿ ÌÌÀÀÀÀÌÌñÿ ÌÌñÿ ÀÀ ÌÌñÿ ÌÌÌÌñÿ ÀÀÌÌÌÌñÿ ÀÀÌÌñÿ ÀÀ ÀÀÌÌñÿ ÌÌÀÀÌÌñÿ ÀÀÌÌÀÀÌÌñÿ ÌÌñÿ ÌÌ ÌÌñÿ ÌÌÌÌñÿ ÌÌÌÌÌÌñÿ ÀÀÌÌñÿ ÌÌ ÀÀÌÌñÿ ÌÌÀÀÌÌñÿ ÌÌÌÌÀÀÌÌñÿ ÌÌñÿ ÀÀ ÌÌñÿ ÀÀ ÌÌñÿ ÀÀÀÀ ÌÌñÿ ÌÌÌÌñÿ ÀÀÌÌÌÌñÿ ÀÀÌÌÌÌñÿ ÀÀÀÀÌÌÌÌñÿ ÌÌñÿ ÌÌ ÌÌñÿ ÀÀ ÌÌñÿ ÌÌÀÀ ÌÌñÿ ÌÌÌÌñÿ ÌÌÌÌÌÌñÿ ÀÀÌÌÌÌñÿ ÌÌÀÀÌÌÌÌñÿ ÌÌñÿ ÀÀ ÌÌñÿ ÌÌ ÌÌñÿ ÀÀÌÌ ÌÌñÿ ÌÌÌÌñÿ ÀÀ ÌÌÌÌñÿ ÌÌÌÌÌÌñÿ ÀÀÌÌÌÌÌÌñÿ ÌÌñÿ ÌÌ ÌÌñÿ ÌÌ ÌÌñÿ ÌÌÌÌ ÌÌñÿ ÌÌÌÌñÿ ÌÌ ÌÌÌÌñÿ ÌÌÌÌÌÌñÿ ÌÌÌÌÌÌÌÌñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þ ñÿ €€€€€€€€ ñÿ ‚ÿ€€€ÿ€ñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿ 8|ÖÖTTTTTñÿ TTTTTÖT8ñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿ  >MEAAc>ñÿ >YQAAc>ñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿ ñÿ ð€x€ÿ€ÿ€€à> ñÿ €€xà€€ÿ€€ÿ€ ñÿ €ð€<à€ÿ€€ÿ€ ñÿ €à<€}€†À|€à ñÿ À|€>à}€†€ð<€ ñÿ €øø‡€x€ðÿ€ÿ€ ñÿ ø€€ð€ð|€ÿ€ÿ€ ñÿ €€ð|Ç€<À>€>À<À ñÿ €ø€ñ€á€>à>  ñÿ €q€Žpà8€ ñÿ à<Ç8€€p€ ñÿ €q€Žpá9€ ñÿ à<Ç8€ƒ€Žp€ ñÿ ÿ€ÿ€€<à<€ ñÿ ÿ€ÿ€à€ð ñÿ €<Ç€<À<à<€ ñÿ ðá€ã€€ð ñÿ Ï0€€ðð€ ñÿ Ï0€À<€x€ ñÿ ß0€€ðð€ÿ€ÿ€ ñÿ ß0€Àx€x€ÿ€ÿ€ñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þ ñÿ 6ã€ÿ€ÿ€ ñÿ €€xø€€ÿ€ ñÿ €À0€8À€ÿ€ ñÿ €€xø€€ÿ€ ñÿ €À0€8À„ÿ€ ñÿ €€ø|€ÿ€ÿ€ÿ€ ñÿ Àp€`€ÿ€ÿ€ÿ€ ñÿ €€ø|€ÿ€ÿ€0 ñÿ Àp€`€ÿ€ÿ€0 ñÿ €à€0€ß0€ß ñÿ €`<€8À€0€ß0€ß ñÿ €à€4€Ï8€ß ñÿ €`<€8À„4€Ï8€ßñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þ ñÿ €€xàã€ã€<€ ñÿ €ð€<ã€<ã€<àñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿþ‚‚‚‚‚‚‚‚‚þñÿ  $H`ñÿ ð È$ ñÿ `H$ ñÿ  $È ð ñÿ ?€@@@@?€ ñÿ ?ÀÀÀ0ñÿ 8|8888888ñÿ 888888|8ñÿ help = 1; } else if ((g_strncasecmp(option, "-kill", 255) == 0) || (g_strncasecmp(option, "--kill", 255) == 0) || (g_strncasecmp(option, "-k", 255) == 0)) { startup_params->kill = 1; } else if ((g_strncasecmp(option, "-nodaemon", 255) == 0) || (g_strncasecmp(option, "--nodaemon", 255) == 0) || (g_strncasecmp(option, "-nd", 255) == 0) || (g_strncasecmp(option, "--nd", 255) == 0) || (g_strncasecmp(option, "-ns", 255) == 0) || (g_strncasecmp(option, "--ns", 255) == 0)) { startup_params->no_daemon = 1; } else if ((g_strncasecmp(option, "-v", 255) == 0) || (g_strncasecmp(option, "--version", 255) == 0)) { startup_params->version = 1; } else if ((g_strncasecmp(option, "-p", 255) == 0) || (g_strncasecmp(option, "--port", 255) == 0)) { index++; g_strncpy(startup_params->port, value, 127); if (g_strlen(startup_params->port) < 1) { g_writeln("error processing params, port [%s]", startup_params->port); return 1; } else { g_writeln("--port parameter found, ini override [%s]", startup_params->port); } } else { return 1; } index++; } return 0; } /*****************************************************************************/ int DEFAULT_CC main(int argc, char** argv) { int test; int host_be; struct xrdp_startup_params* startup_params; int pid; int fd; int no_daemon; char text[256]; char pid_file[256]; g_init("xrdp"); ssl_init(); /* check compiled endian with actual endian */ test = 1; host_be = !((int)(*(unsigned char*)(&test))); #if defined(B_ENDIAN) if (!host_be) #endif #if defined(L_ENDIAN) if (host_be) #endif { g_writeln("endian wrong, edit arch.h"); return 0; } /* check long, int and void* sizes */ if (sizeof(int) != 4) { g_writeln("unusable int size, must be 4"); return 0; } if (sizeof(long) != sizeof(void*)) { g_writeln("long size must match void* size"); return 0; } if (sizeof(long) != 4 && sizeof(long) != 8) { g_writeln("unusable long size, must be 4 or 8"); return 0; } if (sizeof(tui64) != 8) { g_writeln("unusable tui64 size, must be 8"); return 0; } startup_params = (struct xrdp_startup_params*) g_malloc(sizeof(struct xrdp_startup_params), 1); if (xrdp_process_params(argc, argv, startup_params) != 0) { g_writeln("Unknown Parameter"); g_writeln("xrdp -h for help"); g_writeln(""); g_deinit(); g_exit(0); } g_snprintf(pid_file, 255, "%s/xrdp.pid", XRDP_PID_PATH); no_daemon = 0; if (startup_params->kill) { g_writeln("stopping xrdp"); /* read the xrdp.pid file */ fd = -1; if (g_file_exist(pid_file)) /* xrdp.pid */ { fd = g_file_open(pid_file); /* xrdp.pid */ } if (fd == -1) { g_writeln("problem opening to xrdp.pid"); g_writeln("maybe its not running"); } else { g_memset(text, 0, 32); g_file_read(fd, text, 31); pid = g_atoi(text); g_writeln("stopping process id %d", pid); if (pid > 0) { g_sigterm(pid); } g_file_close(fd); } g_deinit(); g_exit(0); } if (startup_params->no_daemon) { no_daemon = 1; } if (startup_params->help) { g_writeln(""); g_writeln("xrdp: A Remote Desktop Protocol server."); g_writeln("Copyright (C) Jay Sorg 2004-2011"); g_writeln("See http://xrdp.sourceforge.net for more information."); g_writeln(""); g_writeln("Usage: xrdp [options]"); g_writeln(" -h: show help"); g_writeln(" -nodaemon: don't fork into background"); g_writeln(" -kill: shut down xrdp"); g_writeln(""); g_deinit(); g_exit(0); } if (startup_params->version) { g_writeln(""); g_writeln("xrdp: A Remote Desktop Protocol server."); g_writeln("Copyright (C) Jay Sorg 2004-2011"); g_writeln("See http://xrdp.sourceforge.net for more information."); g_writeln("Version %s",PACKAGE_VERSION); g_writeln(""); g_deinit(); g_exit(0); } if (g_file_exist(pid_file)) /* xrdp.pid */ { g_writeln("It looks like xrdp is allready running,"); g_writeln("if not delete the xrdp.pid file and try again"); g_deinit(); g_exit(0); } if (!no_daemon) { /* make sure we can write to pid file */ fd = g_file_open(pid_file); /* xrdp.pid */ if (fd == -1) { g_writeln("running in daemon mode with no access to pid files, quitting"); g_deinit(); g_exit(0); } if (g_file_write(fd, "0", 1) == -1) { g_writeln("running in daemon mode with no access to pid files, quitting"); g_deinit(); g_exit(0); } g_file_close(fd); g_file_delete(pid_file); } if (!no_daemon) { /* start of daemonizing code */ pid = g_fork(); if (pid == -1) { g_writeln("problem forking"); g_deinit(); g_exit(1); } if (0 != pid) { g_writeln("process %d started ok", pid); /* exit, this is the main process */ g_deinit(); g_exit(0); } g_sleep(1000); g_file_close(0); g_file_close(1); g_file_close(2); g_file_open("/dev/null"); g_file_open("/dev/null"); g_file_open("/dev/null"); /* end of daemonizing code */ } if (!no_daemon) { /* write the pid to file */ pid = g_getpid(); fd = g_file_open(pid_file); /* xrdp.pid */ if (fd == -1) { g_writeln("trying to write process id to xrdp.pid"); g_writeln("problem opening xrdp.pid"); g_writeln("maybe no rights"); } else { g_sprintf(text, "%d", pid); g_file_write(fd, text, g_strlen(text)); g_file_close(fd); } } g_threadid = tc_get_threadid(); g_listen = xrdp_listen_create(); g_signal_user_interrupt(xrdp_shutdown); /* SIGINT */ g_signal_kill(xrdp_shutdown); /* SIGKILL */ g_signal_pipe(pipe_sig); /* SIGPIPE */ g_signal_terminate(xrdp_shutdown); /* SIGTERM */ g_sync_mutex = tc_mutex_create(); g_sync1_mutex = tc_mutex_create(); pid = g_getpid(); g_snprintf(text, 255, "xrdp_%8.8x_main_term", pid); g_term_event = g_create_wait_obj(text); g_snprintf(text, 255, "xrdp_%8.8x_main_sync", pid); g_sync_event = g_create_wait_obj(text); if (g_term_event == 0) { g_writeln("error creating g_term_event"); } xrdp_listen_main_loop(g_listen, startup_params); xrdp_listen_delete(g_listen); tc_mutex_delete(g_sync_mutex); tc_mutex_delete(g_sync1_mutex); g_delete_wait_obj(g_term_event); g_delete_wait_obj(g_sync_event); /* delete the xrdp.pid file */ g_file_delete(pid_file); g_free(startup_params); g_deinit(); return 0; } xrdp-0.6.0/xrdp/xrdp.h000066400000000000000000000350421203155130500145740ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2004-2010 main include file */ /* include other h files */ #if defined(HAVE_CONFIG_H) #include "config_ac.h" #endif #include "arch.h" #include "parse.h" #include "trans.h" #include "libxrdpinc.h" #include "xrdp_types.h" #include "xrdp_constants.h" #include "defines.h" #include "os_calls.h" #include "ssl_calls.h" #include "thread_calls.h" #include "list.h" #include "file.h" #include "file_loc.h" /* xrdp.c */ long APP_CC g_xrdp_sync(long (*sync_func)(long param1, long param2), long sync_param1, long sync_param2); int APP_CC g_is_term(void); void APP_CC g_set_term(int in_val); tbus APP_CC g_get_term_event(void); tbus APP_CC g_get_sync_event(void); void APP_CC g_loop(void); /* xrdp_cache.c */ struct xrdp_cache* APP_CC xrdp_cache_create(struct xrdp_wm* owner, struct xrdp_session* session, struct xrdp_client_info* client_info); void APP_CC xrdp_cache_delete(struct xrdp_cache* self); int APP_CC xrdp_cache_reset(struct xrdp_cache* self, struct xrdp_client_info* client_info); int APP_CC xrdp_cache_add_bitmap(struct xrdp_cache* self, struct xrdp_bitmap* bitmap); int APP_CC xrdp_cache_add_palette(struct xrdp_cache* self, int* palette); int APP_CC xrdp_cache_add_char(struct xrdp_cache* self, struct xrdp_font_char* font_item); int APP_CC xrdp_cache_add_pointer(struct xrdp_cache* self, struct xrdp_pointer_item* pointer_item); int APP_CC xrdp_cache_add_pointer_static(struct xrdp_cache* self, struct xrdp_pointer_item* pointer_item, int index); int APP_CC xrdp_cache_add_brush(struct xrdp_cache* self, char* brush_item_data); /* xrdp_wm.c */ struct xrdp_wm* APP_CC xrdp_wm_create(struct xrdp_process* owner, struct xrdp_client_info* client_info); void APP_CC xrdp_wm_delete(struct xrdp_wm* self); int APP_CC xrdp_wm_send_palette(struct xrdp_wm* self); int APP_CC xrdp_wm_send_bell(struct xrdp_wm* self); int APP_CC xrdp_wm_load_static_colors(struct xrdp_wm* self); int APP_CC xrdp_wm_load_static_pointers(struct xrdp_wm* self); int APP_CC xrdp_wm_init(struct xrdp_wm* self); int APP_CC xrdp_wm_send_bitmap(struct xrdp_wm* self, struct xrdp_bitmap* bitmap, int x, int y, int cx, int cy); int APP_CC xrdp_wm_set_pointer(struct xrdp_wm* self, int cache_idx); int APP_CC xrdp_wm_set_focused(struct xrdp_wm* self, struct xrdp_bitmap* wnd); int APP_CC xrdp_wm_get_vis_region(struct xrdp_wm* self, struct xrdp_bitmap* bitmap, int x, int y, int cx, int cy, struct xrdp_region* region, int clip_children); int APP_CC xrdp_wm_mouse_move(struct xrdp_wm* self, int x, int y); int APP_CC xrdp_wm_mouse_click(struct xrdp_wm* self, int x, int y, int but, int down); int APP_CC xrdp_wm_key(struct xrdp_wm* self, int device_flags, int scan_code); int APP_CC xrdp_wm_key_sync(struct xrdp_wm* self, int device_flags, int key_flags); int APP_CC xrdp_wm_pu(struct xrdp_wm* self, struct xrdp_bitmap* control); int APP_CC xrdp_wm_send_pointer(struct xrdp_wm* self, int cache_idx, char* data, char* mask, int x, int y); int APP_CC xrdp_wm_pointer(struct xrdp_wm* self, char* data, char* mask, int x, int y); int callback(long id, int msg, long param1, long param2, long param3, long param4); int APP_CC xrdp_wm_delete_all_childs(struct xrdp_wm* self); int APP_CC xrdp_wm_log_msg(struct xrdp_wm* self, char* msg); int APP_CC xrdp_wm_get_wait_objs(struct xrdp_wm* self, tbus* robjs, int* rc, tbus* wobjs, int* wc, int* timeout); int APP_CC xrdp_wm_check_wait_objs(struct xrdp_wm* self); int APP_CC xrdp_wm_set_login_mode(struct xrdp_wm* self, int login_mode); /* xrdp_process.c */ struct xrdp_process* APP_CC xrdp_process_create(struct xrdp_listen* owner, tbus done_event); void APP_CC xrdp_process_delete(struct xrdp_process* self); int APP_CC xrdp_process_main_loop(struct xrdp_process* self); /* xrdp_listen.c */ struct xrdp_listen* APP_CC xrdp_listen_create(void); void APP_CC xrdp_listen_delete(struct xrdp_listen* self); int APP_CC xrdp_listen_main_loop(struct xrdp_listen* self, struct xrdp_startup_params* startup_param); /* xrdp_region.c */ struct xrdp_region* APP_CC xrdp_region_create(struct xrdp_wm* wm); void APP_CC xrdp_region_delete(struct xrdp_region* self); int APP_CC xrdp_region_add_rect(struct xrdp_region* self, struct xrdp_rect* rect); int APP_CC xrdp_region_insert_rect(struct xrdp_region* self, int i, int left, int top, int right, int bottom); int APP_CC xrdp_region_subtract_rect(struct xrdp_region* self, struct xrdp_rect* rect); int APP_CC xrdp_region_get_rect(struct xrdp_region* self, int index, struct xrdp_rect* rect); /* xrdp_bitmap.c */ struct xrdp_bitmap* APP_CC xrdp_bitmap_create(int width, int height, int bpp, int type, struct xrdp_wm* wm); struct xrdp_bitmap* APP_CC xrdp_bitmap_create_with_data(int width, int height, int bpp, char* data, struct xrdp_wm* wm); void APP_CC xrdp_bitmap_delete(struct xrdp_bitmap* self); struct xrdp_bitmap* APP_CC xrdp_bitmap_get_child_by_id(struct xrdp_bitmap* self, int id); int APP_CC xrdp_bitmap_set_focus(struct xrdp_bitmap* self, int focused); int APP_CC xrdp_bitmap_resize(struct xrdp_bitmap* self, int width, int height); int APP_CC xrdp_bitmap_load(struct xrdp_bitmap* self, const char* filename, int* palette); int APP_CC xrdp_bitmap_get_pixel(struct xrdp_bitmap* self, int x, int y); int APP_CC xrdp_bitmap_set_pixel(struct xrdp_bitmap* self, int x, int y, int pixel); int APP_CC xrdp_bitmap_copy_box(struct xrdp_bitmap* self, struct xrdp_bitmap* dest, int x, int y, int cx, int cy); int APP_CC xrdp_bitmap_copy_box_with_crc(struct xrdp_bitmap* self, struct xrdp_bitmap* dest, int x, int y, int cx, int cy); int APP_CC xrdp_bitmap_compare(struct xrdp_bitmap* self, struct xrdp_bitmap* b); int APP_CC xrdp_bitmap_compare_with_crc(struct xrdp_bitmap* self, struct xrdp_bitmap* b); int APP_CC xrdp_bitmap_invalidate(struct xrdp_bitmap* self, struct xrdp_rect* rect); int APP_CC xrdp_bitmap_def_proc(struct xrdp_bitmap* self, int msg, int param1, int param2); int APP_CC xrdp_bitmap_to_screenx(struct xrdp_bitmap* self, int x); int APP_CC xrdp_bitmap_to_screeny(struct xrdp_bitmap* self, int y); int APP_CC xrdp_bitmap_from_screenx(struct xrdp_bitmap* self, int x); int APP_CC xrdp_bitmap_from_screeny(struct xrdp_bitmap* self, int y); int APP_CC xrdp_bitmap_get_screen_clip(struct xrdp_bitmap* self, struct xrdp_painter* painter, struct xrdp_rect* rect, int* dx, int* dy); /* xrdp_painter.c */ struct xrdp_painter* APP_CC xrdp_painter_create(struct xrdp_wm* wm, struct xrdp_session* session); void APP_CC xrdp_painter_delete(struct xrdp_painter* self); int APP_CC xrdp_painter_begin_update(struct xrdp_painter* self); int APP_CC xrdp_painter_end_update(struct xrdp_painter* self); int APP_CC xrdp_painter_font_needed(struct xrdp_painter* self); int APP_CC xrdp_painter_set_clip(struct xrdp_painter* self, int x, int y, int cx, int cy); int APP_CC xrdp_painter_clr_clip(struct xrdp_painter* self); int APP_CC xrdp_painter_fill_rect(struct xrdp_painter* self, struct xrdp_bitmap* bitmap, int x, int y, int cx, int cy); int APP_CC xrdp_painter_draw_bitmap(struct xrdp_painter* self, struct xrdp_bitmap* bitmap, struct xrdp_bitmap* to_draw, int x, int y, int cx, int cy); int APP_CC xrdp_painter_text_width(struct xrdp_painter* self, char* text); int APP_CC xrdp_painter_text_height(struct xrdp_painter* self, char* text); int APP_CC xrdp_painter_draw_text(struct xrdp_painter* self, struct xrdp_bitmap* bitmap, int x, int y, const char* text); int APP_CC xrdp_painter_draw_text2(struct xrdp_painter* self, struct xrdp_bitmap* bitmap, int font, int flags, int mixmode, int clip_left, int clip_top, int clip_right, int clip_bottom, int box_left, int box_top, int box_right, int box_bottom, int x, int y, char* data, int data_len); int APP_CC xrdp_painter_copy(struct xrdp_painter* self, struct xrdp_bitmap* src, struct xrdp_bitmap* dst, int x, int y, int cx, int cy, int srcx, int srcy); int APP_CC xrdp_painter_line(struct xrdp_painter* self, struct xrdp_bitmap* bitmap, int x1, int y1, int x2, int y2); /* xrdp_font.c */ struct xrdp_font* APP_CC xrdp_font_create(struct xrdp_wm* wm); void APP_CC xrdp_font_delete(struct xrdp_font* self); int APP_CC xrdp_font_item_compare(struct xrdp_font_char* font1, struct xrdp_font_char* font2); /* funcs.c */ int APP_CC rect_contains_pt(struct xrdp_rect* in, int x, int y); int APP_CC rect_intersect(struct xrdp_rect* in1, struct xrdp_rect* in2, struct xrdp_rect* out); int APP_CC rect_contained_by(struct xrdp_rect* in1, int left, int top, int right, int bottom); int APP_CC check_bounds(struct xrdp_bitmap* b, int* x, int* y, int* cx, int* cy); int APP_CC add_char_at(char* text, int text_size, twchar ch, int index); int APP_CC remove_char_at(char* text, int text_size, int index); int APP_CC set_string(char** in_str, const char* in); int APP_CC wchar_repeat(twchar* dest, int dest_size_in_wchars, twchar ch, int repeat); /* in lang.c */ struct xrdp_key_info* APP_CC get_key_info_from_scan_code(int device_flags, int scan_code, int* keys, int caps_lock, int num_lock, int scroll_lock, struct xrdp_keymap* keymap); int APP_CC get_keysym_from_scan_code(int device_flags, int scan_code, int* keys, int caps_lock, int num_lock, int scroll_lock, struct xrdp_keymap* keymap); twchar APP_CC get_char_from_scan_code(int device_flags, int scan_code, int* keys, int caps_lock, int num_lock, int scroll_lock, struct xrdp_keymap* keymap); int APP_CC get_keymaps(int keylayout, struct xrdp_keymap* keymap); /* xrdp_login_wnd.c */ int APP_CC xrdp_login_wnd_create(struct xrdp_wm* self); /* xrdp_bitmap_compress.c */ int APP_CC xrdp_bitmap_compress(char* in_data, int width, int height, struct stream* s, int bpp, int byte_limit, int start_line, struct stream* temp, int e); /* xrdp_mm.c */ struct xrdp_mm* APP_CC xrdp_mm_create(struct xrdp_wm* owner); void APP_CC xrdp_mm_delete(struct xrdp_mm* self); int APP_CC xrdp_mm_connect(struct xrdp_mm* self); int APP_CC xrdp_mm_process_channel_data(struct xrdp_mm* self, tbus param1, tbus param2, tbus param3, tbus param4); int APP_CC xrdp_mm_get_wait_objs(struct xrdp_mm* self, tbus* read_objs, int* rcount, tbus* write_objs, int* wcount, int* timeout); int APP_CC xrdp_mm_check_wait_objs(struct xrdp_mm* self); int DEFAULT_CC server_begin_update(struct xrdp_mod* mod); int DEFAULT_CC server_end_update(struct xrdp_mod* mod); int DEFAULT_CC server_bell_trigger(struct xrdp_mod* mod); int DEFAULT_CC server_fill_rect(struct xrdp_mod* mod, int x, int y, int cx, int cy); int DEFAULT_CC server_screen_blt(struct xrdp_mod* mod, int x, int y, int cx, int cy, int srcx, int srcy); int DEFAULT_CC server_paint_rect(struct xrdp_mod* mod, int x, int y, int cx, int cy, char* data, int width, int height, int srcx, int srcy); int DEFAULT_CC server_set_pointer(struct xrdp_mod* mod, int x, int y, char* data, char* mask); int DEFAULT_CC server_palette(struct xrdp_mod* mod, int* palette); int DEFAULT_CC server_msg(struct xrdp_mod* mod, char* msg, int code); int DEFAULT_CC server_is_term(struct xrdp_mod* mod); int DEFAULT_CC server_set_clip(struct xrdp_mod* mod, int x, int y, int cx, int cy); int DEFAULT_CC server_reset_clip(struct xrdp_mod* mod); int DEFAULT_CC server_set_fgcolor(struct xrdp_mod* mod, int fgcolor); int DEFAULT_CC server_set_bgcolor(struct xrdp_mod* mod, int bgcolor); int DEFAULT_CC server_set_opcode(struct xrdp_mod* mod, int opcode); int DEFAULT_CC server_set_mixmode(struct xrdp_mod* mod, int mixmode); int DEFAULT_CC server_set_brush(struct xrdp_mod* mod, int x_orgin, int y_orgin, int style, char* pattern); int DEFAULT_CC server_set_pen(struct xrdp_mod* mod, int style, int width); int DEFAULT_CC server_draw_line(struct xrdp_mod* mod, int x1, int y1, int x2, int y2); int DEFAULT_CC server_add_char(struct xrdp_mod* mod, int font, int charactor, int offset, int baseline, int width, int height, char* data); int DEFAULT_CC server_draw_text(struct xrdp_mod* mod, int font, int flags, int mixmode, int clip_left, int clip_top, int clip_right, int clip_bottom, int box_left, int box_top, int box_right, int box_bottom, int x, int y, char* data, int data_len); int DEFAULT_CC server_reset(struct xrdp_mod* mod, int width, int height, int bpp); int DEFAULT_CC server_query_channel(struct xrdp_mod* mod, int index, char* channel_name, int* channel_flags); int DEFAULT_CC server_get_channel_id(struct xrdp_mod* mod, char* name); int DEFAULT_CC server_send_to_channel(struct xrdp_mod* mod, int channel_id, char* data, int data_len, int total_data_len, int flags); xrdp-0.6.0/xrdp/xrdp.ini000066400000000000000000000014701203155130500151220ustar00rootroot00000000000000 [globals] bitmap_cache=yes bitmap_compression=yes port=3389 crypt_level=low channel_code=1 max_bpp=24 #black=000000 #grey=d6d3ce #dark_grey=808080 #blue=08246b #dark_blue=08246b #white=ffffff #red=ff0000 #green=00ff00 #background=626c72 [xrdp1] name=sesman-Xvnc lib=libvnc.so username=ask password=ask ip=127.0.0.1 port=-1 [xrdp2] name=console lib=libvnc.so ip=127.0.0.1 port=5900 username=na password=ask [xrdp3] name=vnc-any lib=libvnc.so ip=ask port=ask5900 username=na password=ask [xrdp4] name=sesman-any lib=libvnc.so ip=ask port=-1 username=ask password=ask [xrdp5] name=rdp-any lib=librdp.so ip=ask port=ask3389 [xrdp6] name=freerdp-any lib=libxrdpfreerdp1.so ip=ask port=ask3389 username=ask password=ask [xrdp7] name=sesman-X11rdp lib=libxup.so username=ask password=ask ip=127.0.0.1 port=-1 xserverbpp=24 xrdp-0.6.0/xrdp/xrdp24b.bmp000066400000000000000000004400661203155130500154410ustar00rootroot00000000000000BM6@6(À@                   !!!!!!!!!!!!!!!!!!!!!     !!!"""###$$$%%%%%%&&&&&&&&&&&&&&&&&&%%%%%%$$$###"""    !!!"""$$$%%%&&&'''((()))******+++,,,,,,,,,,,,++++++***)))((('''%%%$$$"""    !!!"""###$$$%%%&&&((()))***,,,---...///000000111111111111111111111000///...,,,+++)))'''%%%###!!!   !!!"""$$$$$$&&&&&&'''(((***+++,,,---///000111333444555666666777777777777777777777666555444222000...,,,***(((%%%###!!!   !!!"""###$$$$$$$$$%%%%%%%%%%%%%%%$$$$$$$$$######""""""!!!  !!!!!!"""$$$%%%&&&'''((()))***+++,,,---...///111222333555666888999:::;;;<<<======```}}}€€€}}}```===<<<;;;:::888666444222///---***(((%%%"""    """###%%%&&&'''((()))************************)))))))))(((''''''&&&%%%$$$$$$###"""!!!!!!  !!!"""###$$$%%%&&&'''((()))***,,,---...///000111222333555666777888:::;;;<<<>>>???@@@AAACCCCCCyyyäääøøøäääyyyCCCAAA@@@>>><<<:::888555222000---***'''$$$"""  !!!###$$$&&&(((***+++---...//////000000000000000000/////////......---,,,++++++))))))((('''&&&%%%%%%$$$#########""""""""""""#########$$$%%%&&&'''((()))***+++---...///000222333444666666888999:::;;;<<<>>>???@@@BBBCCCEEEFFFGGGHHHIIIfffÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿfffHHHGGGEEECCC@@@>>>;;;888555222///,,,)))&&&###    """%%%''')))+++---///111222333444555666666666666666666555555555444444333222111000///...---,,,+++******)))((((((((('''''''''''''''((())))))+++,,,---...///000111222444555777888999;;;<<<===>>>???AAABBBCCCDDDEEEGGGHHHJJJKKKMMMNNNOOOPPP€€€äääÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿää䀀€OOOMMMKKKIIIGGGDDDAAA>>>;;;888444111...***'''$$$!!!  !!!$$$&&&)))+++...000222444666888999:::;;;<<<<<<<<<<<<<<<<<<;;;;;;;;;:::999888888777666444333222111000000///...---------,,,,,,,,,,,,------...///000111222333555666777999:::<<<===???@@@AAACCCDDDEEEFFFGGGHHHJJJKKKLLLNNNOOOPPPRRRSSSTTTVVVWWW€€€üüüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüüü€€€UUUTTTRRROOOMMMJJJGGGDDDAAA===:::666222///+++((($$$!!!  !!!$$$'''***---000222555888:::<<<>>>???@@@AAABBBBBBBBBBBBBBBBBBBBBAAAAAA@@@???>>>>>><<<;;;:::999888777666555444333333222222111111111222222333333444666777888999;;;<<<===???@@@BBBDDDEEEGGGHHHJJJKKKLLLMMMNNNOOOPPPRRRSSSTTTVVVWWWYYYZZZ[[[\\\]]]€€€ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ€€€\\\ZZZXXXVVVSSSPPPMMMJJJFFFCCC???;;;777333000,,,((($$$   !!!$$$(((+++...111444777:::===???AAACCCEEEFFFGGGHHHHHHHHHHHHHHHHHHHHHGGGGGGFFFEEEDDDCCCBBBAAA???>>>===<<<;;;:::999999888777777777777666777777888999:::;;;<<<>>>???AAABBBDDDEEEGGGHHHJJJLLLMMMOOOPPPQQQSSSTTTUUUVVVWWWYYYZZZ[[[\\\^^^___aaabbbcccddd€€€ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ€€€bbb```^^^\\\YYYVVVSSSOOOLLLHHHDDD@@@<<<888444000,,,(((###    $$$'''+++///<<>>======<<<<<<<<<<<<<<<<<<===>>>???AAABBBCCCEEEFFFHHHJJJKKKMMMOOOQQQRRRTTTUUUWWWXXXZZZ[[[\\\pkk‚ss||‚ttrnncccdddfffggghhhiiijjj€€€ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ€€€hhhfffdddbbb___\\\XXXUUUQQQMMMIIIEEE@@@<<<888333///+++'''###  """&&&***...===ww€77Æ ôïJJ°vv€QQQLLLNNNPPPRRRSSSSSSTTTYYYuu€PP«í õ22ËxxƒZZZQQQOOONNNMMMLLLozo\\äøä\\mymCCCBBBBBBAAAAAAAAAAAABBBBBBCCCDDDEEEFFFHHHIIIKKKLLL\\\igg{mm‚xxzzrrymmddd\\\^^^___```aaassž^^äøäž^^uujjjlllmmmnnnoooppp€€€ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ€€€nnnllljjjgggmmm‚‚‚nnn\\\FFF@@@<<<777333...***%%%!!!   $$$)))---111eeq88Åÿÿÿÿ..Ïww‚[[[SSSUUUWWWXXXYYY```ww‚55Çÿÿÿÿ00Îqq}VVVUUUTTTRRReje]]ÿÿÿÿÿ\\aeaGGGGGGGGGFFFFFFFFFGGGGGGHHHIIIJJJLLLMMMOOOXXX~rr“ffºBB×((ò ö ãÌ22‘kk‚vvllleeefffuppž^^ÿÿÿÿÿŸ^^zuurrrssstttuuuuuu€€€ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ€€€sssqqquuuƒƒƒ˜˜˜ÔÔÔëëëüüüøøøÞÞÞÄÄÄ›››PPP@@@;;;666111,,,((($$$  """'''+++///444ww€ óÿÿÿÿÿ##ÜxxƒcccZZZ\\\]]]fffyyƒ))Ôÿÿÿÿÿû}}[[[ZZZYYYWWWrräÿÿÿÿÿäq€qLLLLLLLLLKKKKKKKKKLLLLLLMMMNNNOOOQQQSSSjff„xxË22ÿÿÿÿÿÿÿÿÝ""ˆuuvrrlll„uuäÿÿÿÿÿä…wwwwwxxxyyyzzzzzz€€€ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ€€€xxx~~~ŒŒŒäääÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÓÓÓ………fff???999444///***&&&!!!  $$$)))---222666ww€ïÿÿÿÿÿÿåww†jjlaaakkkxx„àÿÿÿÿÿÿö{{‚```^^^]]]\\\~€~üÿÿÿÿÿü~€~QQQQQQPPPPPPPPPPPPQQQQQQRRRSSSTTTVVVlhh”ggðÿÿÿÿÿÿÿÿÿÿó “jj}vv~~üÿÿÿÿÿü~~|||}}}}}}~~~€€€ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ€€€‚‚‚™™™öööÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿõõõ˜˜˜ccc<<<777222---(((###  !!!&&&***///444999bbkKK¯ÿÿÿÿÿÿÿírr‹uuzttˆèÿÿÿÿÿÿÿCCºqq}dddcccbbb```€€€ÿÿÿÿÿÿÿ€€€VVVUUUUUUTTTTTTUUUUUUVVVWWWXXXYYYaaa„xxðÿÿÿÿÿÿÿÿÿÿÿÿö ‡ww€€€ÿÿÿÿÿÿÿ€€€€€€‚‚‚‚‚‚ƒƒƒ€€€ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ€€€ŠŠŠøøøÿÿÿÿÿÿÿÿÿþþþýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿóóó„„„KKK999444///***%%%   """''',,,111666;;;CCCtt~>>¾ÿÿÿÿÿÿÿ óHHµðÿÿÿÿÿÿÿ77Æyyƒjjjhhhgggfffddd€€€ÿÿÿÿÿÿÿ€€€ZZZYYYYYYYYYYYYYYYZZZZZZ[[[\\\]]]€ttË22ÿÿÿÿÿÿô ©TT‰uu†yy¡]]êÿÿÚ%%}}ÿÿÿÿÿÿÿ€€€„„„………………††††††€€€ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ„„„ÞÞÞÿÿÿÿÿÿîîî   „„„ƒƒƒ™™™æææÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÑÑÑ}}}<<<666000+++&&&"""  ###(((---222777<<>>CCCHHHOOOpp{WW¤üÿÿÿÿÿÿÿÿÿÿÿþQQ¬ww‚qqqooonnnnnnlllkkkjjj€€€ÿÿÿÿÿÿÿ€€€`````````___``````aaaaaabbbcccsqq»CCÿÿÿÿÿÿœbb{yyxxxzzz|||~~~€€€‹ttûÿÿÿÿÿÿÿÿÿ€€€‰‰‰ŠŠŠŠŠŠŠŠŠŠŠŠ€€€ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþ•••|||yyyvvvqqqqqq‰‰‰úúúÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¼¼¼aaa888333...)))$$$   $$$***///444999???DDDIIINNNSSSooxbb™øÿÿÿÿÿÿÿÿÿú]] wwrrrqqqqqqpppooonnnmmmlll€€€ÿÿÿÿÿÿÿ€€€ccccccbbbbbbbbbbbbcccdddeeefffrr×((ÿÿÿÿÿì„zzyyy{{{}}}ƒƒƒ‡zzÕ))ÿÿÿÿÿÿÿÿÿ€€€‹‹‹‹‹‹‹‹‹ŒŒŒŒŒŒ€€€ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿèè膆†€€€}}}zzzvvvrrrnnnØØØÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÙÙÙxxx999444...)))$$$    %%%***///555:::???EEEJJJOOOTTTXXXppv__œÿÿÿÿÿÿÿÿÿXX¥xxssssssrrrrrrqqqpppooonnnmmm€€€ÿÿÿÿÿÿÿzƒzfffdddddddddddddddeeeeeefffhhhƒyyò ÿÿÿÿÿÖ((…vv{{{}}}ƒƒƒ„„„ƒ½AAÿÿÿÿÿÿÿÿÿ€€€ŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒ€€€ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÑÑц††€€€}}}zzzvvvrrrnnnvvv¾¾¾ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿóóó:::444///***%%%    %%%***///444:::???EEEIIIOOOSSS^^^xx‚66Çÿÿÿÿÿÿÿÿÿ..Ïzz„uuusssrrrrrrqqqpppooonnnmmm€€€ÿÿÿÿÿÿÿZ¢Zoooeeeeeeeeeeeeeeeffffffgggiiiƒyyò ÿÿÿÿÿÖ((…vv|||~~~€€€‚‚‚„„„………„‚‚½AAÿÿÿÿÿÿÿÿÿ€€€ŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹€€€ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÔÔÔ†††|||yyyuuurrrmmmwwwÂÂÂÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿððð€€€:::444///)))%%%    $$$)))///444999>>>DDDIIINNN]]]yy‚**Óÿÿÿÿÿÿÿÿÿÿÿ$$Úzz„uuuqqqqqqpppooonnnmmmlll€€€ÿÿÿÿÿÿÿ#Û#yƒykkkeeeeeeeeeeeefffggghhhiiiss×((ÿÿÿÿÿì„zz|||~~~€€€‚‚‚„„„………ˆ{{Õ))ÿÿÿÿÿÿÿÿÿ€€€‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠ€€€ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿëëë………}}}zzzwwwtttppplll‚‚‚ÛÛÛÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÕÕÕvvv999333...)))$$$   $$$)))...333888===CCCHHH]]]ww„!!Þÿÿÿÿÿÿÿÿÿÿÿÿÿãww†ttuooonnnnnnmmmlllkkk€€€ÿÿÿÿÿÿÿÿàw†wq€qpppkkknnnppprrrnnnhhhvtt»CCÿÿÿÿÿÿœbb~||}}}ƒƒƒƒƒƒ‹ttûÿÿÿÿÿÿÿÿÿ€€€‰‰‰‰‰‰ˆˆˆˆˆˆ‡‡‡€€€ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿžžž}}}wwwtttqqqmmmqqqŽŽŽýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¸¸¸^^^888333---((($$$  ###(((---222777<<>>??????@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@???????????????>>>>>>???????????????????????????@@@@@@@@@AAABBBCCCDDDEEEGGGHHHIIIJJJLLLNNNOOOQQQSSSTTTVVVWWWYYYZZZZZZ€~~üÿÿÿÿÿü€~~XXXVVVUUUTTTSSSQQQPPPOOOMMMLLLKKKJJJIIIHHHGGGFFFEEECCCBBB@@@>>><<<:::888666333000...+++(((%%%""" ___ƒƒƒººº©©©‡‡‡ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉɾ¾¾………–––*** """$$$'''))),,,...000222444555777888888999999999999::::::::::::::::::::::::999999999999999999999999999999999999::::::::::::::::::;;;<<<<<<===>>>???AAABBBCCCDDDFFFGGGIIIKKKLLLNNNOOOQQQRRRSSSTTT€rräÿÿÿÿÿä€rrQQQPPPNNNMMMLLLKKKIIIHHHGGGFFFDDDCCCBBBAAA@@@???>>>===;;;:::888666444222000...,,,)))'''$$$!!! WWW”””ÇÇÇÉÉÉ•••™™™ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉɺºº„„„   ÉÉÉ»»»}}} !!!###%%%''')))+++---...000111222222333333333333444444444444444444444444333333333333333333333333333444444444444444444444444555555666666777888999;;;<<<===>>>???AAABBBDDDFFFGGGIIIJJJKKKLLLMMMhcc]]ÿÿÿÿÿ]]gbbJJJIIIHHHGGGEEEDDDBBBAAA@@@???>>><<<<<<;;;:::999888666555333222000///---+++)))'''%%%"""  (((‚‚‚ÆÆÆÉÉÉÉÉɈˆˆ­­­ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉɶ¶¶ƒƒƒ§§§ÉÉÉÉÉÉÉÉɯ¯¯www  !!!"""$$$&&&''')))***+++,,,---------------...........................---...------------.........................../////////000111222222333555555777888999:::<<<>>>???AAABBBCCCDDDEEEFFFFFFznn\\äøä\\ynnDDDCCCBBBAAA@@@???===<<<;;;999888777666555444333222111000///---,,,+++)))(((&&&$$$"""   {{{¹¹¹ÉÉÉÉÉÉÇÇÇÅÅÅÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉɯ¯¯‚‚‚­­­ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉžžžhhh  !!!"""$$$%%%&&&&&&'''''''''((((((((((((((((((((((((((((((((((((((((((((((((((((((((())))))))))))))))))))))))******++++++,,,---...///000111222333444666777999:::;;;===>>>>>>???@@@@@@a\\~oo€||~ooa\\>>>>>>===<<<:::999888777666444333222111000///...---,,,+++***)))((('''%%%$$$###!!! 444“““ÉÉÉÉÉÉÉÉɾ¾¾ƒƒƒÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉɪªª‚‚‚³³³ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÈÈÈOOO  !!!!!!"""""""""""""""#####################444@@@MMMNNN(((#####################$$$$$$$$$$$$$$$$$$$$$$$$%%%&&&&&&'''((()))***+++,,,---...///111222444555666777888999999999:::999999999888888777666555444333222111///...---,,,+++***)))(((''''''&&&$$$$$$"""!!!  [[[­­­ÉÉÉÉÉÉÉÉÉÈÈÈÂÂÂÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉ¢¢¢ƒƒƒ¸¸¸ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÅÅŃƒƒ333 ___”””~~~VVV''' !!!"""###$$$$$$%%%&&&'''(((***+++,,,...///000111222222333333333333333333222222111000///...---,,,+++***((('''&&&%%%$$$$$$###"""!!!  yyy¾¾¾ÉÉÉÉÉÉÉÉÉÉÉÉŠŠŠ«««ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉœœœ„„„½½½ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉɾ¾¾~~~ AAA}}}ÆÆÆÉÉÉÉÉÉÉÉÉÀÀÀššš|||+++ !!!"""###$$$%%%'''((()))***+++,,,,,,------------------,,,,,,++++++***)))(((&&&%%%$$$###"""!!!   ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉššš———ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÇÇÇ–––………ÂÂÂÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉ´´´zzz +++VVV|||€€€………ÇÇÇÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉɯ¯¯|||+++ """###$$$%%%&&&&&&''''''((((((((('''''''''&&&&&&%%%$$$###"""!!!  ‚‚‚ÉÉÉÉÉÉÉÉÉÉÉÉÉÉɬ¬¬‡‡‡ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÆÆÆ‘‘‘†††ÄÄÄÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉ£££nnn ###LLLyyy‚‚‚žžžƒƒƒŽŽŽœœœÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉɱ±±||| !!!""""""""""""""""""""""""!!!!!!  ~~~ÇÇÇÉÉÉÉÉÉÉÉÉÉÉÉÁÁÁƒƒƒ³³³ÉÉÉÉÉÉÉÉÉÅÅʼn‰‰ÇÇÇÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉ’’’XXX qqq€€€»»»ÇÇLjˆˆÉÉÉÅÅÅ………­­­ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉ———MMM qqq¹¹¹ÉÉÉÉÉÉÉÉÉÉÉÉÉÉɨ¨¨………ÉÉÉÉÉÉÁÁÁ‰‰‰ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÆÆÆ………;;; sss¤¤¤ÈÈÈÉÉÉÉÉÉ•••„„„ÆÆÆÉÉÉÉÉɺººƒƒƒ¼¼¼ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÀÀÀ}}}  PPP¨¨¨ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÈÈÈŒŒŒššš¿¿¿†††’’’ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÁÁÁ### lllœœœÉÉÉÉÉÉÉÉÉžžžƒƒƒÁÁÁÉÉÉÉÉÉÉÉÉÉÉɨ¨¨‡‡‡ÄÄÄÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉ———FFF  +++ˆˆˆÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉɽ½½‚‚‚ƒƒƒ™™™ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉ···|||ccc”””ÉÉÉÉÉÉÉÉɧ§§ƒƒƒ»»»ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉ•••“““ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉ´´´kkk  rrr±±±ÉÉÉÉÉÉÉÉÉÉÉɹ¹¹’’’‚‚‚‚‚‚ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉ©©©sssWWWÈÈÈÉÉÉÉÉɰ°°‚‚‚²²²ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÇÇLJ‡‡£££ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÄÄÄ}}}  €€€ÅÅÅÈÈȳ³³ŠŠŠ‚‚‚ºººˆˆˆ’’’ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉ———```KKKˆˆˆÆÆÆÉÉÉÉÉɸ¸¸ƒƒƒªªªÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÀÀÀƒƒƒµµµÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉ€€€ VVV’’’………ƒƒƒŽŽŽÀÀÀÉÉÉÉÉÉÁÁÁ………œœœÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÇÇlj‰‰DDD===„„„ÄÄÄÉÉÉÉÉɾ¾¾„„„žžžÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉɰ°°„„„ÀÀÀÉÉÉÉÉÉÉÉÉÉÉÉŠŠŠ((( |||‰‰‰ÀÀÀÉÉÉÉÉÉÉÉÉÉÉÉÉÉɽ½½ƒƒƒ§§§ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÃÃÀ€€)))000ÁÁÁÉÉÉÉÉÉÂÂÂ………’’’ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉ‹‹‹ÇÇÇÉÉÉÉÉÉÉÉÉ„„„~~~»»»ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉ···‚‚‚°°°ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉ»»»}}}%%%¾¾¾ÉÉÉÉÉÉÅÅʼn‰‰ŠŠŠÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉ‹‹‹™™™ÉÉÉÉÉÉÉÉÉ€€€)))¿¿¿ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉɯ¯¯‚‚‚¹¹¹ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉ®®®vvv }}}ºººÉÉÉÉÉÉÇÇdž††ÇÇÇÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÄÄÄ„„„«««ÉÉÉÄÄÄ~~~666‚‚‚ÃÃÃÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉɧ§§ƒƒƒ¿¿¿ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉfff|||µµµÉÉÉÉÉÉÉÉÉ–––ƒƒƒÄÄÄÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉ···‚‚‚»»»£££VVVDDD†††ÆÆÆÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉ„„„ÄÄÄÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÈÈÈŒŒŒMMMxxx¯¯¯ÉÉÉÉÉÉÉÉÉŸŸŸƒƒƒ¾¾¾ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉɤ¤¤†††SSSŒŒŒÇÇÇÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉ”””†††ÇÇÇÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÄÄÄ‚‚‚000 ttt¦¦¦ÉÉÉÉÉÉÉÉɪªª‚‚‚···ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉɇ‡‡rrraaa”””ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÇÇÇŽŽŽ‹‹‹ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉɽ½½~~~mmmŸŸŸÉÉÉÉÉÉÉÉɲ²²‚‚‚®®®ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉ®®®uuukkkÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÅÅʼn‰‰“““ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉɲ²²€€€–––ÉÉÉÉÉÉÉÉɹ¹¹‚‚‚£££ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉɼ¼¼}}} sss¦¦¦ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÁÁÁ………ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉŽŽŽÇÇÇÉÉÉ¿¿¿ƒƒƒ———ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÅÅÅ‚‚‚---xxx¯¯¯ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉɽ½½ƒƒƒ¨¨¨ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÈÈȇ‡‡———ÃÃÆ††ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉŽŽŽNNN|||···ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉ···‚‚‚±±±ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÃÃÄ„„‡‡‡ÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉ¢¢¢kkk~~~»»»ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉɯ¯¯‚‚‚¹¹¹ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉɺººˆˆˆÆÆÆÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉɵµµzzz )))€€€ÀÀÀÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉɧ§§ƒƒƒÀÀÀÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÀÀÀ888‚‚‚ÃÃÃÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉ„„„ÅÅÅÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÇÇdž††:::FFF‡‡‡ÆÆÆÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉ•••‡‡‡ÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉ•••[[[UUUŒŒŒÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÇÇÇŽŽŽŒŒŒÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉɪªªrrrbbb•••ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÅÅʼn‰‰”””ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉɺºº|||lllžžžÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÁÁÁ………žžžÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÃÃÀ€€((( ttt¦¦¦ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉɽ½½ƒƒƒ©©©ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÈÈÈŠŠŠGGGyyy°°°ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉ···‚‚‚±±±ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉžžžfff|||···ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉɯ¯¯‚‚‚¹¹¹ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉɱ±±xxx ~~~¼¼¼ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉɧ§§ƒƒƒÀÀÀÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉɾ¾¾~~~***€€€ÀÀÀÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉ………ÄÄÄÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÆÆÆƒƒƒ333888‚‚‚ÃÃÃÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉ•••ˆˆˆÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉ‘‘‘UUUHHH‡‡‡ÆÆÆÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÇÇÇŒŒŒ½½½ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉɦ¦¦nnnVVVÈÈÈÉÉÉ¿¿¿¯¯¯œœœ‰‰‰‚‚‚¨¨¨ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉ···{{{gggˆˆˆƒƒƒƒƒƒ………›››€€€˜˜˜ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉ“““RRR ttt———¹¹¹ÉÉÉÉÉÉÂÂÂ………ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÃÃÃ,,,mmmžžžÉÉÉÉÉÉÉÉÉÆÆÆ‰‰‰‡‡‡ÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉɼ¼¼}}}ccc•••ÉÉÉÉÉÉÉÉÉÈÈȃƒƒÅÅÅÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉɰ°°xxx VVVÈÈÈÉÉÉÉÉÉÉÉɘ˜˜ƒƒƒÁÁÁÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉŸŸŸjjjIII‡‡‡ÆÆÆÉÉÉÉÉÉÉÉÉ£££‚‚‚ºººÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉRRR999ƒƒƒÄÄÄÉÉÉÉÉÉÉÉÉ­­­‚‚‚²²²ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÅÅŃƒƒ666+++€€€ÁÁÁÉÉÉÉÉÉÉÉÉ···‚‚‚¦¦¦ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉ¿¿¿~~~"""~~~¼¼¼ÉÉÉÉÉÉÉÉɽ½½ƒƒƒ›››ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉɶ¶¶{{{|||···ÉÉÉÉÉÉÉÉÉÂÂÂ………ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉɦ¦¦pppzzz°°°ÉÉÉÉÉÉÉÉÉÆÆÆŠŠŠ‰‰‰ÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉ”””\\\ uuu©©©ÉÉÉÉÉÉÉÉÉÈÈÈ‘‘‘„„„ÇÇÇÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÇÇLJ‡‡AAAnnn   ÉÉÉÉÉÉÉÉÉÉÉÉšššƒƒƒÂÂÂÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉ€€€&&&ddd–––ÉÉÉÉÉÉÉÉÉÉÉɤ¤¤ƒƒƒ¼¼¼ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉɺºº|||YYYÈÈÈÉÉÉÉÉÉÉÉɯ¯¯‚‚‚³³³ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉɱ±±„„„ÃÃÃÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉɬ¬¬uuuJJJˆˆˆÆÆÆÉÉÉÉÉÉÉÉɸ¸¸‚‚‚ªªªÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÁÁÁƒƒƒ‡‡‡ÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉ›››eee;;;ƒƒƒÄÄÄÉÉÉÉÉÉÉÉɾ¾¾ƒƒƒžžžÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉɆ††›››ÇÇÇÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÈÈÈ‹‹‹KKK...€€€ÁÁÁÉÉÉÉÉÉÉÉÉÃÃÆ††“““ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉ”””‹‹‹ÇÇÇÉÉÉÅÅňˆˆ˜˜˜ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÄÄÄ‚‚‚///###~~~½½½ÉÉÉÉÉÉÉÉÉÆÆÆ‹‹‹ŠŠŠÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉɪªªƒƒƒ¿¿¿ÉÉÉÉÉÉÉÉÉÀÀÀ„„„¥¥¥ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉɽ½½~~~}}}¸¸¸ÉÉÉÉÉÉÉÉÉÈÈÈ’’’†††ÇÇÇÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉ¿¿¿‚‚‚¬¬¬ÉÉÉÉÉÉÉÉÉÉÉÉÉÉɹ¹¹ƒƒƒ°°°ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉɳ³³yyy zzz±±±ÉÉÉÉÉÉÉÉÉÉÉÉ›››ƒƒƒÃÃÃÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÇÇdž††```………ÅÅÅÉÉÉÉÉÉÉÉÉÉÉÉÉÉɯ¯¯‚‚‚ºººÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉ¢¢¢lll vvvªªªÉÉÉÉÉÉÉÉÉÉÉɦ¦¦‚‚‚½½½ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉɘ˜˜^^^NNN‰‰‰ÇÇÇÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉ£££ƒƒƒÂÂÂÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉ‘‘‘VVVooo¡¡¡ÉÉÉÉÉÉÉÉÉÉÉɰ°°‚‚‚¶¶¶ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉ«««ttt[[[ÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉɘ˜˜†††ÇÇÇÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÆÆÆOOOfff˜˜˜ÉÉÉÉÉÉÉÉÉÉÉɸ¸¸ƒƒƒ¬¬¬ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉ»»»}}}fff˜˜˜ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÇÇÇŽŽŽ‹‹‹ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉɬ¬¬‚‚‚yyy[[[ÈÈÈÉÉÉÉÉÉÉÉÉ¿¿¿ƒƒƒ¡¡¡ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÄÄÄ+++ooo   ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÄÄĈˆˆ•••ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÄÄăƒƒªªª‹‹‹333LLL‰‰‰ÇÇÇÉÉÉÉÉÉÉÉÉÃÃLJ‡•••ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉŒŒŒLLL uuu¨¨¨ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉ¿¿¿„„„¢¢¢ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉ‹‹‹ŽŽŽÉÉÉ···sssXXXƒƒƒ………‰‰‰˜˜˜¡¡¡ŠŠŠ‹‹‹ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉ   iiiyyy°°°ÉÉÉÉÉÉÉÉÉÉÉÉÉÉɹ¹¹ƒƒƒ®®®ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉ«««ƒƒƒÀÀÀÉÉÉÈÈÈ~~~ }}}¶¶¶¶¶¶­­­¤¤¤———ˆˆˆ’’’ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉ´´´yyy |||···ÉÉÉÉÉÉÉÉÉÉÉÉÉÉɯ¯¯‚‚‚¹¹¹ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÃÃꪪÉÉÉÉÉÉÉÉÉ„„„ RRRšššÉÉÉÉÉÉÉÉÉÉÉÉÇÇLjˆˆ   ŠŠŠ’’’ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÀÀÀ~~~~~~»»»ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉ¢¢¢ƒƒƒÁÁÁÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉ‹‹‹ŽŽŽÉÉÉÉÉÉÉÉÉÉÉÉššš:::ÅÅÅÉÉÉÉÉÉÉÉÉÉÉÉ¢¢¢‡‡‡ÉÉÉÅÅÅ‹‹‹ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÇÇÇ………888)))¿¿¿ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉ———………ÆÆÆÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉ«««ƒƒƒÀÀÀÉÉÉÉÉÉÉÉÉÉÉÉ©©©NNNbbbªªªÉÉÉÉÉÉÉÉÉÉÉɽ½½‚‚‚»»»ÉÉÉÉÉÉÅÅÅŽŽŽÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉ”””ZZZ555‚‚‚ÃÃÃÉÉÉÉÉÉÉÉÉÉÉÉÇÇlj‰‰ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉɃƒƒªªªÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉ¢¢¢???{{{ÁÁÁÉÉÉÉÉÉÉÉÉÉÉÉššš‘‘‘ÉÉÉÉÉÉÉÉÉÉÉÉÆÆÆŽŽŽ‹‹‹ÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉ©©©rrrCCC………ÅÅÅÉÉÉÉÉÉÉÉÉÉÉÉÄÄ懇’’’ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉŠŠŠŽŽŽÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉ–––444ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉŒŒŒ©©©ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÆÆÆ‘‘‘ˆˆˆÇÇÇÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉɹ¹¹|||QQQŠŠŠÇÇÇÉÉÉÉÉÉÉÉÉÉÉÉ¿¿¿ƒƒƒŸŸŸÉÉÉÉÉÉÉÉÉÉÉÉÉÉɪªªƒƒƒÀÀÀÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉ‹‹‹***(((‰‰‰ÉÉÉÉÉÉÉÉÉÉÉÉÉÉɃƒƒ¿¿¿ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÇÇÇ’’’ˆˆˆÆÆÆÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÃÃÀ€€''']]]‘‘‘ÈÈÈÉÉÉÉÉÉÉÉÉÉÉɸ¸¸‚‚‚¬¬¬ÉÉÉÉÉÉÉÉɃƒƒªªªÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÅÅÅ~~~ CCC¡¡¡ÉÉÉÉÉÉÉÉÉÉÉÉÁÁÁ‚‚‚ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÇÇÇ•••†††ÄÄÄÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÈÈÈŠŠŠFFFggg™™™ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉ­­­‚‚‚···ÉÉÉÉÉɉ‰‰ŽŽŽÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉɦ¦¦YYYQQQªªªÉÉÉÉÉÉÉÉÉÉÉÉ´´´‡‡‡ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÈÈÈ–––†††ÃÃÃÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉeeeppp¡¡¡ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉ¢¢¢ƒƒƒ¿¿¿§§§‚‚‚ÀÀÀÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÈÈÈ€€€000ÉÉÉÉÉÉÉÉÉÉÉɰ°°ˆˆˆÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÈÈÈššš„„„ÂÂÂÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉɱ±±xxx yyy„„„ŠŠŠ•••žžž¦¦¦®®®ŒŒŒƒƒƒƒƒƒªªªÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÈÈÈ‘‘‘```€€€ÉÉÉÉÉÉÉÉÉÉÉɽ½½ƒƒƒÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉ›››„„„ÀÀÀÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉɾ¾¾~~~nnn€€€„„„‡‡‡………„„„‚‚‚€€€ƒƒƒ³³³ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÈÈÈ‘‘‘aaa|||ÂÂÂÉÉÉÉÉÉÉÉÉÈÈÈ‚‚‚ÁÁÁÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉžžžƒƒƒ½½½ÉÉÉÉÉÉÉÉÉÉÉÉÆÆÆƒƒƒ333555|||†††”””¢¢¢¬¬¬‚‚‚¢¢¢ÂÂÂÉÉÉÁÁÁ©©©………```ddd¬¬¬ÉÉÉÉÉÉÉÉÉÉÉÉŒŒŒ©©©ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉ   ƒƒƒ¼¼¼ÉÉÉÉÉÉÉÉÉ’’’UUU"""333@@@TTTgggvvv|||||||||WWW'''~~~¿¿¿ÉÉÉÉÉÉÉÉÉœœœ‘‘‘ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉ£££ƒƒƒºººÉÉɦ¦¦ooo666„„„ÇÇÇÉÉÉÉÉɽ½½‚‚‚¶¶¶ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉɦ¦¦ƒƒƒ§§§{{{YYY•••ÉÉÉÉÉÉÉÉÉ¥¥¥„„„ÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉœœœ%%%pppŒŒŒ¾¾¾ÉÉÉÈÈÈ”””ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉɪªª{{{---:::|||™™™ÁÁÁ¾¾¾ƒƒƒ‘‘‘ÄÄÄÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÈÈÈ›››ttt NNN{{{€€€ŒŒŒ€€€ƒƒƒ¡¡¡ÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÃÃꪪ………eee222YYYzzz€€€€€€ŠŠŠ–––¦¦¦§§§†††}}}YYY&&& '''555EEEPPP&&&xrdp-0.6.0/xrdp/xrdp256.bmp000077500000000000000000001401761203155130500153700ustar00rootroot00000000000000BM~À~(ÀÀ  333fff™™™ÌÌÌÿÿÿ€€`€ €€€€ÿÀÀÀðûÿÈÐÔÀ  À €ÀÀ ÿÿ                                                                                                                                                                                                 xrdp-0.6.0/xrdp/xrdp_bitmap.c000066400000000000000000001411561203155130500161270ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2004-2010 bitmap, drawable this is a object that can be drawn on with a painter all windows, bitmaps, even the screen are of this type maybe it should be called xrdp_drawable */ #include "xrdp.h" static int g_crc_seed = 0xffffffff; static int g_crc_table[256] = { 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d }; #define CRC_START(in_crc) (in_crc) = g_crc_seed #define CRC_PASS(in_pixel, in_crc) \ (in_crc) = g_crc_table[((in_crc) ^ (in_pixel)) & 0xff] ^ ((in_crc) >> 8) #define CRC_END(in_crc) (in_crc) = ((in_crc) ^ g_crc_seed) /*****************************************************************************/ struct xrdp_bitmap* APP_CC xrdp_bitmap_create(int width, int height, int bpp, int type, struct xrdp_wm* wm) { struct xrdp_bitmap* self = (struct xrdp_bitmap *)NULL; int Bpp = 0; self = (struct xrdp_bitmap*)g_malloc(sizeof(struct xrdp_bitmap), 1); self->type = type; self->width = width; self->height = height; self->bpp = bpp; Bpp = 4; switch (bpp) { case 8: Bpp = 1; break; case 15: Bpp = 2; break; case 16: Bpp = 2; break; } if (self->type == WND_TYPE_BITMAP || self->type == WND_TYPE_IMAGE) { self->data = (char*)g_malloc(width * height * Bpp, 0); } if (self->type != WND_TYPE_BITMAP) { self->child_list = list_create(); } self->line_size = width * Bpp; if (self->type == WND_TYPE_COMBO) { self->string_list = list_create(); self->string_list->auto_free = 1; self->data_list = list_create(); self->data_list->auto_free = 1; } self->wm = wm; return self; } /*****************************************************************************/ struct xrdp_bitmap* APP_CC xrdp_bitmap_create_with_data(int width, int height, int bpp, char* data, struct xrdp_wm* wm) { struct xrdp_bitmap* self = (struct xrdp_bitmap *)NULL; self = (struct xrdp_bitmap*)g_malloc(sizeof(struct xrdp_bitmap), 1); self->type = WND_TYPE_BITMAP; self->width = width; self->height = height; self->bpp = bpp; self->data = data; self->do_not_free_data = 1; self->wm = wm; return self; } /*****************************************************************************/ void APP_CC xrdp_bitmap_delete(struct xrdp_bitmap* self) { int i = 0; struct xrdp_mod_data* mod_data = (struct xrdp_mod_data *)NULL; if (self == 0) { return; } if (self->wm != 0) { if (self->wm->focused_window != 0) { if (self->wm->focused_window->focused_control == self) { self->wm->focused_window->focused_control = 0; } } if (self->wm->focused_window == self) { self->wm->focused_window = 0; } if (self->wm->dragging_window == self) { self->wm->dragging_window = 0; } if (self->wm->button_down == self) { self->wm->button_down = 0; } if (self->wm->popup_wnd == self) { self->wm->popup_wnd = 0; } if (self->wm->login_window == self) { self->wm->login_window = 0; } if (self->wm->log_wnd == self) { self->wm->log_wnd = 0; } } if (self->child_list != 0) { for (i = self->child_list->count - 1; i >= 0; i--) { xrdp_bitmap_delete((struct xrdp_bitmap*)self->child_list->items[i]); } list_delete(self->child_list); } if (self->parent != 0) { i = list_index_of(self->parent->child_list, (long)self); if (i >= 0) { list_remove_item(self->parent->child_list, i); } } if (self->string_list != 0) /* for combo */ { list_delete(self->string_list); } if (self->data_list != 0) /* for combo */ { for (i = 0; i < self->data_list->count; i++) { mod_data = (struct xrdp_mod_data*)list_get_item(self->data_list, i); if (mod_data != 0) { list_delete(mod_data->names); list_delete(mod_data->values); } } list_delete(self->data_list); } if (!self->do_not_free_data) { g_free(self->data); } g_free(self->caption1); g_free(self); } /*****************************************************************************/ struct xrdp_bitmap* APP_CC xrdp_bitmap_get_child_by_id(struct xrdp_bitmap* self, int id) { int i = 0; struct xrdp_bitmap* b = (struct xrdp_bitmap *)NULL; for (i = 0; i < self->child_list->count; i++) { b = (struct xrdp_bitmap*)list_get_item(self->child_list, i); if (b->id == id) { return b; } } return 0; } /*****************************************************************************/ /* if focused is true focus this window else unfocus it */ /* returns error */ int APP_CC xrdp_bitmap_set_focus(struct xrdp_bitmap* self, int focused) { struct xrdp_painter* painter = (struct xrdp_painter *)NULL; if (self == 0) { return 0; } if (self->type != WND_TYPE_WND) /* 1 */ { return 0; } painter = xrdp_painter_create(self->wm, self->wm->session); xrdp_painter_font_needed(painter); xrdp_painter_begin_update(painter); if (focused) { /* active title bar */ painter->fg_color = self->wm->blue; xrdp_painter_fill_rect(painter, self, 3, 3, self->width - 5, 18); painter->fg_color = self->wm->white; } else { /* inactive title bar */ painter->fg_color = self->wm->dark_grey; xrdp_painter_fill_rect(painter, self, 3, 3, self->width - 5, 18); painter->fg_color = self->wm->black; } xrdp_painter_draw_text(painter, self, 4, 4, self->caption1); xrdp_painter_end_update(painter); xrdp_painter_delete(painter); return 0; } /*****************************************************************************/ static int APP_CC xrdp_bitmap_get_index(struct xrdp_bitmap* self, int* palette, int color) { int r = 0; int g = 0; int b = 0; r = (color & 0xff0000) >> 16; g = (color & 0x00ff00) >> 8; b = (color & 0x0000ff) >> 0; r = (r >> 5) << 0; g = (g >> 5) << 3; b = (b >> 6) << 6; return (b | g | r); } /*****************************************************************************/ /* returns error */ int APP_CC xrdp_bitmap_resize(struct xrdp_bitmap* self, int width, int height) { int Bpp = 0; if ((width == self->width) && (height == self->height)) { return 0; } if (self->do_not_free_data) { return 1; } self->width = width; self->height = height; Bpp = 4; switch (self->bpp) { case 8: Bpp = 1; break; case 15: Bpp = 2; break; case 16: Bpp = 2; break; } g_free(self->data); self->data = (char*)g_malloc(width * height * Bpp, 0); self->line_size = width * Bpp; return 0; } /*****************************************************************************/ /* load a bmp file */ /* return 0 ok */ /* return 1 error */ int APP_CC xrdp_bitmap_load(struct xrdp_bitmap* self, const char* filename, int* palette) { int fd = 0; int i = 0; int j = 0; int k = 0; int color = 0; int size = 0; int palette1[256]; char type1[4]; struct xrdp_bmp_header header; struct stream* s = (struct stream *)NULL; g_memset(palette1,0,sizeof(int) * 256); g_memset(type1,0,sizeof(char) * 4); g_memset(&header,0,sizeof(struct xrdp_bmp_header)); if (!g_file_exist(filename)) { g_writeln("xrdp_bitmap_load: error bitmap file [%s] does not exist", filename); return 1; } s = (struct stream *)NULL; fd = g_file_open(filename); if (fd != -1) { /* read file type */ if (g_file_read(fd, type1, 2) != 2) { g_writeln("xrdp_bitmap_load: error bitmap file [%s] read error", filename); g_file_close(fd); return 1; } if ((type1[0] != 'B') || (type1[1] != 'M')) { g_writeln("xrdp_bitmap_load: error bitmap file [%s] not BMP file", filename); g_file_close(fd); return 1; } /* read file size */ make_stream(s); init_stream(s, 8192); g_file_read(fd, s->data, 4); in_uint32_le(s, size); /* read bmp header */ g_file_seek(fd, 14); init_stream(s, 8192); g_file_read(fd, s->data, 40); /* size better be 40 */ in_uint32_le(s, header.size); in_uint32_le(s, header.image_width); in_uint32_le(s, header.image_height); in_uint16_le(s, header.planes); in_uint16_le(s, header.bit_count); in_uint32_le(s, header.compression); in_uint32_le(s, header.image_size); in_uint32_le(s, header.x_pels_per_meter); in_uint32_le(s, header.y_pels_per_meter); in_uint32_le(s, header.clr_used); in_uint32_le(s, header.clr_important); if ((header.bit_count != 4) && (header.bit_count != 8) && (header.bit_count != 24)) { g_writeln("xrdp_bitmap_load: error bitmap file [%s] bad bpp %d", filename, header.bit_count); free_stream(s); g_file_close(fd); return 1; } if (header.bit_count == 24) /* 24 bit bitmap */ { g_file_seek(fd, 14 + header.size); xrdp_bitmap_resize(self, header.image_width, header.image_height); size = header.image_width * header.image_height * 3; init_stream(s, size); /* read data */ for (i = header.image_height - 1; i >= 0; i--) { size = header.image_width * 3; k = g_file_read(fd, s->data + i * size, size); if (k != size) { g_writeln("xrdp_bitmap_load: error bitmap file [%s] read", filename); } } for (i = 0; i < self->height; i++) { for (j = 0; j < self->width; j++) { in_uint8(s, k); color = k; in_uint8(s, k); color |= k << 8; in_uint8(s, k); color |= k << 16; if (self->bpp == 8) { color = xrdp_bitmap_get_index(self, palette, color); } else if (self->bpp == 15) { color = COLOR15((color & 0xff0000) >> 16, (color & 0x00ff00) >> 8, (color & 0x0000ff) >> 0); } else if (self->bpp == 16) { color = COLOR16((color & 0xff0000) >> 16, (color & 0x00ff00) >> 8, (color & 0x0000ff) >> 0); } xrdp_bitmap_set_pixel(self, j, i, color); } } } else if (header.bit_count == 8) /* 8 bit bitmap */ { /* read palette */ g_file_seek(fd, 14 + header.size); init_stream(s, 8192); g_file_read(fd, s->data, header.clr_used * sizeof(int)); for (i = 0; i < header.clr_used; i++) { in_uint32_le(s, palette1[i]); } xrdp_bitmap_resize(self, header.image_width, header.image_height); size = header.image_width * header.image_height; init_stream(s, size); /* read data */ for (i = header.image_height - 1; i >= 0; i--) { size = header.image_width; k = g_file_read(fd, s->data + i * size, size); if (k != size) { g_writeln("xrdp_bitmap_load: error bitmap file [%s] read", filename); } } for (i = 0; i < self->height; i++) { for (j = 0; j < self->width; j++) { in_uint8(s, k); color = palette1[k]; if (self->bpp == 8) { color = xrdp_bitmap_get_index(self, palette, color); } else if (self->bpp == 15) { color = COLOR15((color & 0xff0000) >> 16, (color & 0x00ff00) >> 8, (color & 0x0000ff) >> 0); } else if (self->bpp == 16) { color = COLOR16((color & 0xff0000) >> 16, (color & 0x00ff00) >> 8, (color & 0x0000ff) >> 0); } xrdp_bitmap_set_pixel(self, j, i, color); } } } else if (header.bit_count == 4) /* 4 bit bitmap */ { /* read palette */ g_file_seek(fd, 14 + header.size); init_stream(s, 8192); g_file_read(fd, s->data, header.clr_used * sizeof(int)); for (i = 0; i < header.clr_used; i++) { in_uint32_le(s, palette1[i]); } xrdp_bitmap_resize(self, header.image_width, header.image_height); size = (header.image_width * header.image_height) / 2; init_stream(s, size); /* read data */ for (i = header.image_height - 1; i >= 0; i--) { size = header.image_width / 2; k = g_file_read(fd, s->data + i * size, size); if (k != size) { g_writeln("xrdp_bitmap_load: error bitmap file [%s] read", filename); } } for (i = 0; i < self->height; i++) { for (j = 0; j < self->width; j++) { if ((j & 1) == 0) { in_uint8(s, k); color = (k >> 4) & 0xf; } else { color = k & 0xf; } color = palette1[color]; if (self->bpp == 8) { color = xrdp_bitmap_get_index(self, palette, color); } else if (self->bpp == 15) { color = COLOR15((color & 0xff0000) >> 16, (color & 0x00ff00) >> 8, (color & 0x0000ff) >> 0); } else if (self->bpp == 16) { color = COLOR16((color & 0xff0000) >> 16, (color & 0x00ff00) >> 8, (color & 0x0000ff) >> 0); } xrdp_bitmap_set_pixel(self, j, i, color); } } } g_file_close(fd); free_stream(s); } else { g_writeln("xrdp_bitmap_load: error loading bitmap from file [%s]", filename); return 1; } return 0; } /*****************************************************************************/ int APP_CC xrdp_bitmap_get_pixel(struct xrdp_bitmap* self, int x, int y) { if (self == 0) { return 0; } if (self->data == 0) { return 0; } if (x >= 0 && x < self->width && y >= 0 && y < self->height) { if (self->bpp == 8) { return GETPIXEL8(self->data, x, y, self->width); } else if (self->bpp == 15 || self->bpp == 16) { return GETPIXEL16(self->data, x, y, self->width); } else if (self->bpp == 24) { return GETPIXEL32(self->data, x, y, self->width); } } return 0; } /*****************************************************************************/ int APP_CC xrdp_bitmap_set_pixel(struct xrdp_bitmap* self, int x, int y, int pixel) { if (self == 0) { return 0; } if (self->data == 0) { return 0; } if (x >= 0 && x < self->width && y >= 0 && y < self->height) { if (self->bpp == 8) { SETPIXEL8(self->data, x, y, self->width, pixel); } else if (self->bpp == 15 || self->bpp == 16) { SETPIXEL16(self->data, x, y, self->width, pixel); } else if (self->bpp == 24) { SETPIXEL32(self->data, x, y, self->width, pixel); } } return 0; } /*****************************************************************************/ /* copy part of self at x, y to 0, 0 in dest */ /* returns error */ int APP_CC xrdp_bitmap_copy_box(struct xrdp_bitmap* self, struct xrdp_bitmap* dest, int x, int y, int cx, int cy) { int i = 0; int j = 0; int destx = 0; int desty = 0; int pixel = 0; if (self == 0) { return 1; } if (dest == 0) { return 1; } if (self->type != WND_TYPE_BITMAP && self->type != WND_TYPE_IMAGE) { return 1; } if (dest->type != WND_TYPE_BITMAP && dest->type != WND_TYPE_IMAGE) { return 1; } if (self->bpp != dest->bpp) { return 1; } destx = 0; desty = 0; if (!check_bounds(self, &x, &y, &cx, &cy)) { return 1; } if (!check_bounds(dest, &destx, &desty, &cx, &cy)) { return 1; } if (self->bpp == 24) { for (i = 0; i < cy; i++) { for (j = 0; j < cx; j++) { pixel = GETPIXEL32(self->data, j + x, i + y, self->width); SETPIXEL32(dest->data, j + destx, i + desty, dest->width, pixel); } } } else if (self->bpp == 15 || self->bpp == 16) { for (i = 0; i < cy; i++) { for (j = 0; j < cx; j++) { pixel = GETPIXEL16(self->data, j + x, i + y, self->width); SETPIXEL16(dest->data, j + destx, i + desty, dest->width, pixel); } } } else if (self->bpp == 8) { for (i = 0; i < cy; i++) { for (j = 0; j < cx; j++) { pixel = GETPIXEL8(self->data, j + x, i + y, self->width); SETPIXEL8(dest->data, j + destx, i + desty, dest->width, pixel); } } } else { return 1; } return 0; } /*****************************************************************************/ /* copy part of self at x, y to 0, 0 in dest */ /* returns error */ int APP_CC xrdp_bitmap_copy_box_with_crc(struct xrdp_bitmap* self, struct xrdp_bitmap* dest, int x, int y, int cx, int cy) { int i = 0; int j = 0; int destx = 0; int desty = 0; int pixel = 0; int crc = 0; int incs = 0; int incd = 0; unsigned char* s8 = (unsigned char *)NULL; unsigned char* d8 = (unsigned char *)NULL; unsigned short* s16 = (unsigned short *)NULL; unsigned short* d16 = (unsigned short *)NULL; if (self == 0) { return 1; } if (dest == 0) { return 1; } if (self->type != WND_TYPE_BITMAP && self->type != WND_TYPE_IMAGE) { return 1; } if (dest->type != WND_TYPE_BITMAP && dest->type != WND_TYPE_IMAGE) { return 1; } if (self->bpp != dest->bpp) { return 1; } destx = 0; desty = 0; if (!check_bounds(self, &x, &y, &cx, &cy)) { return 1; } if (!check_bounds(dest, &destx, &desty, &cx, &cy)) { return 1; } CRC_START(crc); if (self->bpp == 24) { for (i = 0; i < cy; i++) { for (j = 0; j < cx; j++) { pixel = GETPIXEL32(self->data, j + x, i + y, self->width); CRC_PASS(pixel, crc); CRC_PASS(pixel >> 8, crc); CRC_PASS(pixel >> 16, crc); SETPIXEL32(dest->data, j + destx, i + desty, dest->width, pixel); } } } else if (self->bpp == 15 || self->bpp == 16) { s16 = ((unsigned short*)(self->data)) + (self->width * y + x); d16 = ((unsigned short*)(dest->data)) + (dest->width * desty + destx); incs = self->width - cx; incd = dest->width - cx; for (i = 0; i < cy; i++) { for (j = 0; j < cx; j++) { pixel = *s16; CRC_PASS(pixel, crc); CRC_PASS(pixel >> 8, crc); *d16 = pixel; s16++; d16++; } s16 += incs; d16 += incd; } } else if (self->bpp == 8) { s8 = ((unsigned char*)(self->data)) + (self->width * y + x); d8 = ((unsigned char*)(dest->data)) + (dest->width * desty + destx); incs = self->width - cx; incd = dest->width - cx; for (i = 0; i < cy; i++) { for (j = 0; j < cx; j++) { pixel = *s8; CRC_PASS(pixel, crc); *d8 = pixel; s8++; d8++; } s8 += incs; d8 += incd; } } else { return 1; } CRC_END(crc); dest->crc = crc; return 0; } /*****************************************************************************/ /* returns true if they are the same, else returns false */ int APP_CC xrdp_bitmap_compare(struct xrdp_bitmap* self, struct xrdp_bitmap* b) { if (self == 0) { return 0; } if (b == 0) { return 0; } if (self->bpp != b->bpp) { return 0; } if (self->width != b->width) { return 0; } if (self->height != b->height) { return 0; } if (g_memcmp(self->data, b->data, b->height * b->line_size) == 0) { return 1; } return 0; } /*****************************************************************************/ /* returns true if they are the same, else returns false */ int APP_CC xrdp_bitmap_compare_with_crc(struct xrdp_bitmap* self, struct xrdp_bitmap* b) { if (self == 0) { return 0; } if (b == 0) { return 0; } if (self->bpp != b->bpp) { return 0; } if (self->width != b->width) { return 0; } if (self->height != b->height) { return 0; } if (self->crc == b->crc) { return 1; } return 0; } /*****************************************************************************/ static int APP_CC xrdp_bitmap_draw_focus_box(struct xrdp_bitmap* self, struct xrdp_painter* painter, int x, int y, int cx, int cy) { painter->rop = 0xf0; xrdp_painter_begin_update(painter); painter->use_clip = 0; painter->mix_mode = 1; painter->brush.pattern[0] = 0xaa; painter->brush.pattern[1] = 0x55; painter->brush.pattern[2] = 0xaa; painter->brush.pattern[3] = 0x55; painter->brush.pattern[4] = 0xaa; painter->brush.pattern[5] = 0x55; painter->brush.pattern[6] = 0xaa; painter->brush.pattern[7] = 0x55; painter->brush.x_orgin = x; painter->brush.x_orgin = x; painter->brush.style = 3; painter->fg_color = self->wm->black; painter->bg_color = self->parent->bg_color; /* top */ xrdp_painter_fill_rect(painter, self, x, y, cx, 1); /* bottom */ xrdp_painter_fill_rect(painter, self, x, y + (cy - 1), cx, 1); /* left */ xrdp_painter_fill_rect(painter, self, x, y + 1, 1, cy - 2); /* right */ xrdp_painter_fill_rect(painter, self, x + (cx - 1), y + 1, 1, cy - 2); xrdp_painter_end_update(painter); painter->rop = 0xcc; painter->mix_mode = 0; return 0; } /*****************************************************************************/ /* x and y are in relation to self for 0, 0 is the top left of the control */ static int APP_CC xrdp_bitmap_draw_button(struct xrdp_bitmap* self, struct xrdp_painter* painter, int x, int y, int w, int h, int down) { if (down) { /* gray box */ painter->fg_color = self->wm->grey; xrdp_painter_fill_rect(painter, self, x, y, w, h); /* black top line */ painter->fg_color = self->wm->black; xrdp_painter_fill_rect(painter, self, x, y, w, 1); /* black left line */ painter->fg_color = self->wm->black; xrdp_painter_fill_rect(painter, self, x, y, 1, h); /* dark grey top line */ painter->fg_color = self->wm->dark_grey; xrdp_painter_fill_rect(painter, self, x + 1, y + 1, w - 2, 1); /* dark grey left line */ painter->fg_color = self->wm->dark_grey; xrdp_painter_fill_rect(painter, self, x + 1, y + 1, 1, h - 2); /* dark grey bottom line */ painter->fg_color = self->wm->dark_grey; xrdp_painter_fill_rect(painter, self, x + 1, y + (h - 2), w - 1, 1); /* dark grey right line */ painter->fg_color = self->wm->dark_grey; xrdp_painter_fill_rect(painter, self, x + (w - 2), y + 1, 1, h - 1); /* black bottom line */ painter->fg_color = self->wm->black; xrdp_painter_fill_rect(painter, self, x, y + (h - 1), w, 1); /* black right line */ painter->fg_color = self->wm->black; xrdp_painter_fill_rect(painter, self, x + (w - 1), y, 1, h); } else { /* gray box */ painter->fg_color = self->wm->grey; xrdp_painter_fill_rect(painter, self, x, y, w, h); /* white top line */ painter->fg_color = self->wm->white; xrdp_painter_fill_rect(painter, self, x, y, w, 1); /* white left line */ painter->fg_color = self->wm->white; xrdp_painter_fill_rect(painter, self, x, y, 1, h); /* dark grey bottom line */ painter->fg_color = self->wm->dark_grey; xrdp_painter_fill_rect(painter, self, x + 1, y + (h - 2), w - 1, 1); /* dark grey right line */ painter->fg_color = self->wm->dark_grey; xrdp_painter_fill_rect(painter, self, (x + w) - 2, y + 1, 1, h - 1); /* black bottom line */ painter->fg_color = self->wm->black; xrdp_painter_fill_rect(painter, self, x, y + (h - 1), w, 1); /* black right line */ painter->fg_color = self->wm->black; xrdp_painter_fill_rect(painter, self, x + (w - 1), y, 1, h); } return 0; } /*****************************************************************************/ /* nil for rect means the whole thing */ /* returns error */ int APP_CC xrdp_bitmap_invalidate(struct xrdp_bitmap* self, struct xrdp_rect* rect) { int i; int w; int h; int x; int y; struct xrdp_bitmap* b; struct xrdp_rect r1; struct xrdp_rect r2; struct xrdp_painter* painter; twchar wtext[256]; char text[256]; char* p; if (self == 0) /* if no bitmap */ { return 0; } if (self->type == WND_TYPE_BITMAP) /* if 0, bitmap, leave */ { return 0; } painter = xrdp_painter_create(self->wm, self->wm->session); xrdp_painter_font_needed(painter); painter->rop = 0xcc; /* copy */ if (rect == 0) { painter->use_clip = 0; } else { if (ISRECTEMPTY(*rect)) { xrdp_painter_delete(painter); return 0; } painter->clip = *rect; painter->use_clip = &painter->clip; } xrdp_painter_begin_update(painter); if (self->type == WND_TYPE_WND) /* 1 */ { /* draw grey background */ painter->fg_color = self->bg_color; xrdp_painter_fill_rect(painter, self, 0, 0, self->width, self->height); /* top white line */ painter->fg_color = self->wm->white; xrdp_painter_fill_rect(painter, self, 1, 1, self->width - 2, 1); /* left white line */ painter->fg_color = self->wm->white; xrdp_painter_fill_rect(painter, self, 1, 1, 1, self->height - 2); /* bottom dark grey line */ painter->fg_color = self->wm->dark_grey; xrdp_painter_fill_rect(painter, self, 1, self->height - 2, self->width - 2, 1); /* right dark grey line */ painter->fg_color = self->wm->dark_grey; xrdp_painter_fill_rect(painter, self, self->width - 2, 1, 1, self->height - 2); /* bottom black line */ painter->fg_color = self->wm->black; xrdp_painter_fill_rect(painter, self, 0, self->height - 1, self->width, 1); /* right black line */ painter->fg_color = self->wm->black; xrdp_painter_fill_rect(painter, self, self->width - 1, 0, 1, self->height); if (self->wm->focused_window == self) { /* active title bar */ painter->fg_color = self->wm->blue; xrdp_painter_fill_rect(painter, self, 3, 3, self->width - 5, 18); painter->fg_color = self->wm->white; } else { /* inactive title bar */ painter->fg_color = self->wm->dark_grey; xrdp_painter_fill_rect(painter, self, 3, 3, self->width - 5, 18); painter->fg_color = self->wm->black; } xrdp_painter_draw_text(painter, self, 4, 4, self->caption1); } else if (self->type == WND_TYPE_SCREEN) /* 2 */ { if (self->wm->mm->mod != 0) { if (self->wm->mm->mod->mod_event != 0) { if (rect != 0) { x = rect->left; y = rect->top; w = rect->right - rect->left; h = rect->bottom - rect->top; if (check_bounds(self->wm->screen, &x, &y, &w, &h)) { self->wm->mm->mod->mod_event(self->wm->mm->mod, WM_INVALIDATE, MAKELONG(y, x), MAKELONG(h, w), 0, 0); } } else { x = 0; y = 0; w = self->wm->screen->width; h = self->wm->screen->height; self->wm->mm->mod->mod_event(self->wm->mm->mod, WM_INVALIDATE, MAKELONG(y, x), MAKELONG(h, w), 0, 0); } } } else { painter->fg_color = self->bg_color; xrdp_painter_fill_rect(painter, self, 0, 0, self->width, self->height); } } else if (self->type == WND_TYPE_BUTTON) /* 3 */ { if (self->state == BUTTON_STATE_UP) /* 0 */ { xrdp_bitmap_draw_button(self, painter, 0, 0, self->width, self->height, 0); w = xrdp_painter_text_width(painter, self->caption1); h = xrdp_painter_text_height(painter, self->caption1); painter->fg_color = self->wm->black; xrdp_painter_draw_text(painter, self, self->width / 2 - w / 2, self->height / 2 - h / 2, self->caption1); if (self->parent != 0) { if (self->wm->focused_window == self->parent) { if (self->parent->focused_control == self) { xrdp_bitmap_draw_focus_box(self, painter, 4, 4, self->width - 8, self->height - 8); } } } } else if (self->state == BUTTON_STATE_DOWN) /* 1 */ { xrdp_bitmap_draw_button(self, painter, 0, 0, self->width, self->height, 1); w = xrdp_painter_text_width(painter, self->caption1); h = xrdp_painter_text_height(painter, self->caption1); painter->fg_color = self->wm->black; xrdp_painter_draw_text(painter, self, (self->width / 2 - w / 2) + 1, (self->height / 2 - h / 2) + 1, self->caption1); if (self->parent != 0) if (self->wm->focused_window == self->parent) if (self->parent->focused_control == self) xrdp_bitmap_draw_focus_box(self, painter, 4, 4, self->width - 8, self->height - 8); } } else if (self->type == WND_TYPE_IMAGE) /* 4 */ { xrdp_painter_copy(painter, self, self, 0, 0, self->width, self->height, 0, 0); } else if (self->type == WND_TYPE_EDIT) /* 5 */ { /* draw gray box */ painter->fg_color = self->wm->grey; xrdp_painter_fill_rect(painter, self, 0, 0, self->width, self->height); /* main white background */ painter->fg_color = self->wm->white; xrdp_painter_fill_rect(painter, self, 1, 1, self->width - 3, self->height - 3); /* dark grey top line */ painter->fg_color = self->wm->dark_grey; xrdp_painter_fill_rect(painter, self, 0, 0, self->width, 1); /* dark grey left line */ painter->fg_color = self->wm->dark_grey; xrdp_painter_fill_rect(painter, self, 0, 0, 1, self->height); /* white bottom line */ painter->fg_color = self->wm->white; xrdp_painter_fill_rect(painter, self, 0, self->height- 1, self->width, 1); /* white right line */ painter->fg_color = self->wm->white; xrdp_painter_fill_rect(painter, self, self->width - 1, 0, 1, self->height); /* black left line */ painter->fg_color = self->wm->black; xrdp_painter_fill_rect(painter, self, 1, 1, 1, self->height - 3); /* black top line */ painter->fg_color = self->wm->black; xrdp_painter_fill_rect(painter, self, 1, 1, self->width - 3, 1); /* draw text */ painter->fg_color = self->wm->black; if (self->password_char != 0) { i = g_mbstowcs(0, self->caption1, 0); g_memset(text, self->password_char, i); text[i] = 0; xrdp_painter_draw_text(painter, self, 4, 2, text); } else { xrdp_painter_draw_text(painter, self, 4, 2, self->caption1); } /* draw xor box(cursor) */ if (self->parent != 0) { if (self->parent->focused_control == self) { if (self->password_char != 0) { wchar_repeat(wtext, 255, self->password_char, self->edit_pos); wtext[self->edit_pos] = 0; g_wcstombs(text, wtext, 255); } else { g_mbstowcs(wtext, self->caption1, 255); wtext[self->edit_pos] = 0; g_wcstombs(text, wtext, 255); } w = xrdp_painter_text_width(painter, text); painter->fg_color = self->wm->white; painter->rop = 0x5a; xrdp_painter_fill_rect(painter, self, 4 + w, 3, 2, self->height - 6); } } /* reset rop back */ painter->rop = 0xcc; } else if (self->type == WND_TYPE_LABEL) /* 6 */ { painter->fg_color = self->wm->black; xrdp_painter_draw_text(painter, self, 0, 0, self->caption1); } else if (self->type == WND_TYPE_COMBO) /* 7 combo box */ { /* draw gray box */ painter->fg_color = self->wm->grey; xrdp_painter_fill_rect(painter, self, 0, 0, self->width, self->height); /* white background */ painter->fg_color = self->wm->white; xrdp_painter_fill_rect(painter, self, 1, 1, self->width - 3, self->height - 3); if (self->parent->focused_control == self) { painter->fg_color = self->wm->dark_blue; xrdp_painter_fill_rect(painter, self, 3, 3, (self->width - 6) - 18, self->height - 5); } /* dark grey top line */ painter->fg_color = self->wm->dark_grey; xrdp_painter_fill_rect(painter, self, 0, 0, self->width, 1); /* dark grey left line */ painter->fg_color = self->wm->dark_grey; xrdp_painter_fill_rect(painter, self, 0, 0, 1, self->height); /* white bottom line */ painter->fg_color = self->wm->white; xrdp_painter_fill_rect(painter, self, 0, self->height- 1, self->width, 1); /* white right line */ painter->fg_color = self->wm->white; xrdp_painter_fill_rect(painter, self, self->width - 1, 0, 1, self->height); /* black left line */ painter->fg_color = self->wm->black; xrdp_painter_fill_rect(painter, self, 1, 1, 1, self->height - 3); /* black top line */ painter->fg_color = self->wm->black; xrdp_painter_fill_rect(painter, self, 1, 1, self->width - 3, 1); /* draw text */ if (self->parent->focused_control == self) { painter->fg_color = self->wm->white; } else { painter->fg_color = self->wm->black; } xrdp_painter_draw_text(painter, self, 4, 2, (char*)list_get_item(self->string_list, self->item_index)); /* draw button on right */ x = self->width - 20; y = 2; w = (self->width - x) - 2; h = self->height - 4; /* looks better with a background around */ painter->fg_color = self->wm->grey; xrdp_painter_fill_rect(painter, self, x, y, w, h); if (self->state == BUTTON_STATE_UP) /* 0 */ { xrdp_bitmap_draw_button(self, painter, x+1, y+1, w-1, h-1, 0); } else { xrdp_bitmap_draw_button(self, painter, x+1, y+1, w-1, h-1, 1); } /* draw the arrow */ w = w / 2; x = x + (w / 2) + 1; h = (h / 2) + 2; y = y + (h / 2) + 1; painter->fg_color = self->wm->black; for (i=w; i>0; i=i-2) { xrdp_painter_fill_rect(painter, self, x, y, i, 1); y++; x = x + 1; } } else if (self->type == WND_TYPE_SPECIAL) /* 8 special */ { if (self->popped_from != 0) { /* change height if there are too many items in the list */ i = xrdp_painter_text_height(painter, "W"); i = self->popped_from->string_list->count * i; if (i > self->height) { self->height = i; } } painter->fg_color = self->wm->white; xrdp_painter_fill_rect(painter, self, 0, 0, self->width, self->height); /* draw the list items */ if (self->popped_from != 0) { y = 0; for (i = 0; i < self->popped_from->string_list->count; i++) { p = (char*)list_get_item(self->popped_from->string_list, i); h = xrdp_painter_text_height(painter, p); self->item_height = h; if (i == self->item_index) { painter->fg_color = self->wm->blue; xrdp_painter_fill_rect(painter, self, 0, y, self->width, h); painter->fg_color = self->wm->white; } else { painter->fg_color = self->wm->black; } xrdp_painter_draw_text(painter, self, 2, y, p); y = y + h; } } } /* notify */ if (self->notify != 0) { self->notify(self, self, WM_PAINT, (long)painter, 0); /* 3 */ } /* draw any child windows in the area */ for (i = 0; i < self->child_list->count; i++) { b = (struct xrdp_bitmap*)list_get_item(self->child_list, i); if (rect == 0) { xrdp_bitmap_invalidate(b, 0); } else { MAKERECT(r1, b->left, b->top, b->width, b->height); if (rect_intersect(rect, &r1, &r2)) { RECTOFFSET(r2, -(b->left), -(b->top)); xrdp_bitmap_invalidate(b, &r2); } } } xrdp_painter_end_update(painter); xrdp_painter_delete(painter); return 0; } /*****************************************************************************/ /* returns error */ int APP_CC xrdp_bitmap_def_proc(struct xrdp_bitmap* self, int msg, int param1, int param2) { twchar c; int n; int i; int shift; int ext; int scan_code; int num_bytes; int num_chars; struct xrdp_bitmap* b; struct xrdp_bitmap* focus_out_control; if (self == 0) { return 0; } if (self->wm == 0) { return 0; } if (self->type == WND_TYPE_WND) { if (msg == WM_KEYDOWN) { scan_code = param1 % 128; if (scan_code == 15) /* tab */ { /* move to next tab stop */ shift = self->wm->keys[42] || self->wm->keys[54]; i = -1; if (self->child_list != 0) { i = list_index_of(self->child_list, (long)self->focused_control); } if (shift) { i--; if (i < 0) { i = self->child_list->count - 1; } } else { i++; if (i >= self->child_list->count) { i = 0; } } n = self->child_list->count; b = (struct xrdp_bitmap*)list_get_item(self->child_list, i); while (b != self->focused_control && b != 0 && n > 0) { n--; if (b->tab_stop) { focus_out_control = self->focused_control; self->focused_control = b; xrdp_bitmap_invalidate(focus_out_control, 0); xrdp_bitmap_invalidate(b, 0); break; } if (shift) { i--; if (i < 0) { i = self->child_list->count - 1; } } else { i++; if (i >= self->child_list->count) { i = 0; } } b = (struct xrdp_bitmap*)list_get_item(self->child_list, i); } } else if (scan_code == 28) /* enter */ { if (self->default_button != 0) { if (self->notify != 0) { /* I think this should use def_proc */ self->notify(self, self->default_button, 1, 0, 0); return 0; } } } else if (scan_code == 1) /* esc */ { if (self->esc_button != 0) { if (self->notify != 0) { /* I think this should use def_proc */ self->notify(self, self->esc_button, 1, 0, 0); return 0; } } } } if (self->focused_control != 0) { xrdp_bitmap_def_proc(self->focused_control, msg, param1, param2); } } else if (self->type == WND_TYPE_EDIT) { if (msg == WM_KEYDOWN) { scan_code = param1 % 128; ext = param2 & 0x0100; /* left or up arrow */ if ((scan_code == 75 || scan_code == 72) && (ext || self->wm->num_lock == 0)) { if (self->edit_pos > 0) { self->edit_pos--; xrdp_bitmap_invalidate(self, 0); } } /* right or down arrow */ else if ((scan_code == 77 || scan_code == 80) && (ext || self->wm->num_lock == 0)) { if (self->edit_pos < g_mbstowcs(0, self->caption1, 0)) { self->edit_pos++; xrdp_bitmap_invalidate(self, 0); } } /* backspace */ else if (scan_code == 14) { n = g_mbstowcs(0, self->caption1, 0); if (n > 0) { if (self->edit_pos > 0) { self->edit_pos--; remove_char_at(self->caption1, 255, self->edit_pos); xrdp_bitmap_invalidate(self, 0); } } } /* delete */ else if (scan_code == 83 && (ext || self->wm->num_lock == 0)) { n = g_mbstowcs(0, self->caption1, 0); if (n > 0) { if (self->edit_pos < n) { remove_char_at(self->caption1, 255, self->edit_pos); xrdp_bitmap_invalidate(self, 0); } } } /* end */ else if (scan_code == 79 && (ext || self->wm->num_lock == 0)) { n = g_mbstowcs(0, self->caption1, 0); if (self->edit_pos < n) { self->edit_pos = n; xrdp_bitmap_invalidate(self, 0); } } /* home */ else if ((scan_code == 71) && (ext || (self->wm->num_lock == 0))) { if (self->edit_pos > 0) { self->edit_pos = 0; xrdp_bitmap_invalidate(self, 0); } } else { c = get_char_from_scan_code (param2, scan_code, self->wm->keys, self->wm->caps_lock, self->wm->num_lock, self->wm->scroll_lock, &(self->wm->keymap)); num_chars = g_mbstowcs(0, self->caption1, 0); num_bytes = g_strlen(self->caption1); if ((c >= 32) && (num_chars < 127) && (num_bytes < 250)) { add_char_at(self->caption1, 255, c, self->edit_pos); self->edit_pos++; xrdp_bitmap_invalidate(self, 0); } } } } else if (self->type == WND_TYPE_COMBO) { if (msg == WM_KEYDOWN) { scan_code = param1 % 128; ext = param2 & 0x0100; /* left or up arrow */ if (((scan_code == 75) || (scan_code == 72)) && (ext || (self->wm->num_lock == 0))) { if (self->item_index > 0) { self->item_index--; xrdp_bitmap_invalidate(self, 0); if (self->parent->notify != 0) { self->parent->notify(self->parent, self, CB_ITEMCHANGE, 0, 0); } } } /* right or down arrow */ else if ((scan_code == 77 || scan_code == 80) && (ext || self->wm->num_lock == 0)) { if ((self->item_index + 1) < self->string_list->count) { self->item_index++; xrdp_bitmap_invalidate(self, 0); if (self->parent->notify != 0) { self->parent->notify(self->parent, self, CB_ITEMCHANGE, 0, 0); } } } } } else if (self->type == WND_TYPE_SPECIAL) { if (msg == WM_MOUSEMOVE) { if (self->item_height > 0 && self->popped_from != 0) { i = param2; i = i / self->item_height; if (i != self->item_index && i < self->popped_from->string_list->count) { self->item_index = i; xrdp_bitmap_invalidate(self, 0); } } } else if (msg == WM_LBUTTONUP) { if (self->popped_from != 0) { self->popped_from->item_index = self->item_index; xrdp_bitmap_invalidate(self->popped_from, 0); if (self->popped_from->parent->notify != 0) { self->popped_from->parent->notify(self->popped_from->parent, self->popped_from, CB_ITEMCHANGE, 0, 0); } } } } return 0; } /*****************************************************************************/ /* convert the controls coords to screen coords */ int APP_CC xrdp_bitmap_to_screenx(struct xrdp_bitmap* self, int x) { int i; i = x; while (self != 0) { i = i + self->left; self = self->parent; } return i; } /*****************************************************************************/ /* convert the controls coords to screen coords */ int APP_CC xrdp_bitmap_to_screeny(struct xrdp_bitmap* self, int y) { int i; i = y; while (self != 0) { i = i + self->top; self = self->parent; } return i; } /*****************************************************************************/ /* convert the screen coords to controls coords */ int APP_CC xrdp_bitmap_from_screenx(struct xrdp_bitmap* self, int x) { int i; i = x; while (self != 0) { i = i - self->left; self = self->parent; } return i; } /*****************************************************************************/ /* convert the screen coords to controls coords */ int APP_CC xrdp_bitmap_from_screeny(struct xrdp_bitmap* self, int y) { int i; i = y; while (self != 0) { i = i - self->top; self = self->parent; } return i; } /*****************************************************************************/ int APP_CC xrdp_bitmap_get_screen_clip(struct xrdp_bitmap* self, struct xrdp_painter* painter, struct xrdp_rect* rect, int* dx, int* dy) { int ldx; int ldy; if (painter->use_clip) { *rect = painter->clip; } else { rect->left = 0; rect->top = 0; rect->right = self->width; rect->bottom = self->height; } ldx = xrdp_bitmap_to_screenx(self, 0); ldy = xrdp_bitmap_to_screeny(self, 0); rect->left += ldx; rect->top += ldy; rect->right += ldx; rect->bottom += ldy; if (dx != 0) { *dx = ldx; } if (dy != 0) { *dy = ldy; } return 0; } xrdp-0.6.0/xrdp/xrdp_cache.c000066400000000000000000000351301203155130500157100ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2004-2010 cache */ #include "xrdp.h" /*****************************************************************************/ struct xrdp_cache* APP_CC xrdp_cache_create(struct xrdp_wm* owner, struct xrdp_session* session, struct xrdp_client_info* client_info) { struct xrdp_cache* self; self = (struct xrdp_cache*)g_malloc(sizeof(struct xrdp_cache), 1); self->wm = owner; self->session = session; self->use_bitmap_comp = client_info->use_bitmap_comp; self->cache1_entries = client_info->cache1_entries; self->cache1_size = client_info->cache1_size; self->cache2_entries = client_info->cache2_entries; self->cache2_size = client_info->cache2_size; self->cache3_entries = client_info->cache3_entries; self->cache3_size = client_info->cache3_size; self->bitmap_cache_persist_enable = client_info->bitmap_cache_persist_enable; self->bitmap_cache_version = client_info->bitmap_cache_version; self->pointer_cache_entries = client_info->pointer_cache_entries; return self; } /*****************************************************************************/ void APP_CC xrdp_cache_delete(struct xrdp_cache* self) { int i; int j; if (self == 0) { return; } /* free all the cached bitmaps */ for (i = 0; i < 3; i++) { for (j = 0; j < 2000; j++) { xrdp_bitmap_delete(self->bitmap_items[i][j].bitmap); } } /* free all the cached font items */ for (i = 0; i < 12; i++) { for (j = 0; j < 256; j++) { g_free(self->char_items[i][j].font_item.data); } } g_free(self); } /*****************************************************************************/ int APP_CC xrdp_cache_reset(struct xrdp_cache* self, struct xrdp_client_info* client_info) { struct xrdp_wm* wm; struct xrdp_session* session; int i; int j; /* free all the cached bitmaps */ for (i = 0; i < 3; i++) { for (j = 0; j < 2000; j++) { xrdp_bitmap_delete(self->bitmap_items[i][j].bitmap); } } /* free all the cached font items */ for (i = 0; i < 12; i++) { for (j = 0; j < 256; j++) { g_free(self->char_items[i][j].font_item.data); } } /* save these */ wm = self->wm; session = self->session; /* set whole struct to zero */ g_memset(self, 0, sizeof(struct xrdp_cache)); /* set some stuff back */ self->wm = wm; self->session = session; self->use_bitmap_comp = client_info->use_bitmap_comp; self->cache1_entries = client_info->cache1_entries; self->cache1_size = client_info->cache1_size; self->cache2_entries = client_info->cache2_entries; self->cache2_size = client_info->cache2_size; self->cache3_entries = client_info->cache3_entries; self->cache3_size = client_info->cache3_size; self->bitmap_cache_persist_enable = client_info->bitmap_cache_persist_enable; self->bitmap_cache_version = client_info->bitmap_cache_version; self->pointer_cache_entries = client_info->pointer_cache_entries; return 0; } /*****************************************************************************/ /* returns cache id */ int APP_CC xrdp_cache_add_bitmap(struct xrdp_cache* self, struct xrdp_bitmap* bitmap) { int i = 0; int j = 0; int oldest = 0; int cache_id = 0; int cache_idx = 0; int bmp_size = 0; int e = 0; int Bpp = 0; e = bitmap->width % 4; if (e != 0) { e = 4 - e; } Bpp = (bitmap->bpp + 7) / 8; bmp_size = (bitmap->width + e) * bitmap->height * Bpp; self->bitmap_stamp++; /* look for match */ if (bmp_size <= self->cache1_size) { i = 0; for (j = 0; j < self->cache1_entries; j++) { #ifdef USE_CRC if (xrdp_bitmap_compare_with_crc(self->bitmap_items[i][j].bitmap, bitmap)) #else if (xrdp_bitmap_compare(self->bitmap_items[i][j].bitmap, bitmap)) #endif { self->bitmap_items[i][j].stamp = self->bitmap_stamp; DEBUG(("found bitmap at %d %d", i, j)); xrdp_bitmap_delete(bitmap); return MAKELONG(j, i); } } } else if (bmp_size <= self->cache2_size) { i = 1; for (j = 0; j < self->cache2_entries; j++) { #ifdef USE_CRC if (xrdp_bitmap_compare_with_crc(self->bitmap_items[i][j].bitmap, bitmap)) #else if (xrdp_bitmap_compare(self->bitmap_items[i][j].bitmap, bitmap)) #endif { self->bitmap_items[i][j].stamp = self->bitmap_stamp; DEBUG(("found bitmap at %d %d", i, j)); xrdp_bitmap_delete(bitmap); return MAKELONG(j, i); } } } else if (bmp_size <= self->cache3_size) { i = 2; for (j = 0; j < self->cache3_entries; j++) { #ifdef USE_CRC if (xrdp_bitmap_compare_with_crc(self->bitmap_items[i][j].bitmap, bitmap)) #else if (xrdp_bitmap_compare(self->bitmap_items[i][j].bitmap, bitmap)) #endif { self->bitmap_items[i][j].stamp = self->bitmap_stamp; DEBUG(("found bitmap at %d %d", i, j)); xrdp_bitmap_delete(bitmap); return MAKELONG(j, i); } } } else { g_writeln("error in xrdp_cache_add_bitmap, too big(%d)", bmp_size); } /* look for oldest */ cache_id = 0; cache_idx = 0; oldest = 0x7fffffff; if (bmp_size <= self->cache1_size) { i = 0; for (j = 0; j < self->cache1_entries; j++) { if (self->bitmap_items[i][j].stamp < oldest) { oldest = self->bitmap_items[i][j].stamp; cache_id = i; cache_idx = j; } } } else if (bmp_size <= self->cache2_size) { i = 1; for (j = 0; j < self->cache2_entries; j++) { if (self->bitmap_items[i][j].stamp < oldest) { oldest = self->bitmap_items[i][j].stamp; cache_id = i; cache_idx = j; } } } else if (bmp_size <= self->cache3_size) { i = 2; for (j = 0; j < self->cache3_entries; j++) { if (self->bitmap_items[i][j].stamp < oldest) { oldest = self->bitmap_items[i][j].stamp; cache_id = i; cache_idx = j; } } } DEBUG(("adding bitmap at %d %d", cache_id, cache_idx)); /* set, send bitmap and return */ xrdp_bitmap_delete(self->bitmap_items[cache_id][cache_idx].bitmap); self->bitmap_items[cache_id][cache_idx].bitmap = bitmap; self->bitmap_items[cache_id][cache_idx].stamp = self->bitmap_stamp; if (self->bitmap_cache_version == 0) /* orginal version */ { if (self->use_bitmap_comp) { libxrdp_orders_send_bitmap(self->session, bitmap->width, bitmap->height, bitmap->bpp, bitmap->data, cache_id, cache_idx); } else { libxrdp_orders_send_raw_bitmap(self->session, bitmap->width, bitmap->height, bitmap->bpp, bitmap->data, cache_id, cache_idx); } } else { if (self->use_bitmap_comp) { libxrdp_orders_send_bitmap2(self->session, bitmap->width, bitmap->height, bitmap->bpp, bitmap->data, cache_id, cache_idx); } else { libxrdp_orders_send_raw_bitmap2(self->session, bitmap->width, bitmap->height, bitmap->bpp, bitmap->data, cache_id, cache_idx); } } return MAKELONG(cache_idx, cache_id); } /*****************************************************************************/ /* not used */ /* not sure how to use a palette in rdp */ int APP_CC xrdp_cache_add_palette(struct xrdp_cache* self, int* palette) { int i; int oldest; int index; if (self == 0) { return 0; } if (palette == 0) { return 0; } if (self->wm->screen->bpp > 8) { return 0; } self->palette_stamp++; /* look for match */ for (i = 0; i < 6; i++) { if (g_memcmp(palette, self->palette_items[i].palette, 256 * sizeof(int)) == 0) { self->palette_items[i].stamp = self->palette_stamp; return i; } } /* look for oldest */ index = 0; oldest = 0x7fffffff; for (i = 0; i < 6; i++) { if (self->palette_items[i].stamp < oldest) { oldest = self->palette_items[i].stamp; index = i; } } /* set, send palette and return */ g_memcpy(self->palette_items[index].palette, palette, 256 * sizeof(int)); self->palette_items[index].stamp = self->palette_stamp; libxrdp_orders_send_palette(self->session, palette, index); return index; } /*****************************************************************************/ int APP_CC xrdp_cache_add_char(struct xrdp_cache* self, struct xrdp_font_char* font_item) { int i; int j; int oldest; int f; int c; int datasize; struct xrdp_font_char* fi; self->char_stamp++; /* look for match */ for (i = 7; i < 12; i++) { for (j = 0; j < 250; j++) { if (xrdp_font_item_compare(&self->char_items[i][j].font_item, font_item)) { self->char_items[i][j].stamp = self->char_stamp; DEBUG(("found font at %d %d", i, j)); return MAKELONG(j, i); } } } /* look for oldest */ f = 0; c = 0; oldest = 0x7fffffff; for (i = 7; i < 12; i++) { for (j = 0; j < 250; j++) { if (self->char_items[i][j].stamp < oldest) { oldest = self->char_items[i][j].stamp; f = i; c = j; } } } DEBUG(("adding char at %d %d", f, c)); /* set, send char and return */ fi = &self->char_items[f][c].font_item; g_free(fi->data); datasize = FONT_DATASIZE(font_item); fi->data = (char*)g_malloc(datasize, 1); g_memcpy(fi->data, font_item->data, datasize); fi->offset = font_item->offset; fi->baseline = font_item->baseline; fi->width = font_item->width; fi->height = font_item->height; self->char_items[f][c].stamp = self->char_stamp; libxrdp_orders_send_font(self->session, fi, f, c); return MAKELONG(c, f); } /*****************************************************************************/ /* added the pointer to the cache and send it to client, it also sets the client if it finds it returns the index in the cache does not take ownership of pointer_item */ int APP_CC xrdp_cache_add_pointer(struct xrdp_cache* self, struct xrdp_pointer_item* pointer_item) { int i; int oldest; int index; if (self == 0) { return 0; } self->pointer_stamp++; /* look for match */ for (i = 2; i < self->pointer_cache_entries; i++) { if (self->pointer_items[i].x == pointer_item->x && self->pointer_items[i].y == pointer_item->y && g_memcmp(self->pointer_items[i].data, pointer_item->data, 32 * 32 * 3) == 0 && g_memcmp(self->pointer_items[i].mask, pointer_item->mask, 32 * 32 / 8) == 0) { self->pointer_items[i].stamp = self->pointer_stamp; xrdp_wm_set_pointer(self->wm, i); self->wm->current_pointer = i; DEBUG(("found pointer at %d", i)); return i; } } /* look for oldest */ index = 2; oldest = 0x7fffffff; for (i = 2; i < self->pointer_cache_entries; i++) { if (self->pointer_items[i].stamp < oldest) { oldest = self->pointer_items[i].stamp; index = i; } } self->pointer_items[index].x = pointer_item->x; self->pointer_items[index].y = pointer_item->y; g_memcpy(self->pointer_items[index].data, pointer_item->data, 32 * 32 * 3); g_memcpy(self->pointer_items[index].mask, pointer_item->mask, 32 * 32 / 8); self->pointer_items[index].stamp = self->pointer_stamp; xrdp_wm_send_pointer(self->wm, index, self->pointer_items[index].data, self->pointer_items[index].mask, self->pointer_items[index].x, self->pointer_items[index].y); self->wm->current_pointer = index; DEBUG(("adding pointer at %d", index)); return index; } /*****************************************************************************/ /* this does not take owership of pointer_item, it makes a copy */ int APP_CC xrdp_cache_add_pointer_static(struct xrdp_cache* self, struct xrdp_pointer_item* pointer_item, int index) { if (self == 0) { return 0; } self->pointer_items[index].x = pointer_item->x; self->pointer_items[index].y = pointer_item->y; g_memcpy(self->pointer_items[index].data, pointer_item->data, 32 * 32 * 3); g_memcpy(self->pointer_items[index].mask, pointer_item->mask, 32 * 32 / 8); self->pointer_items[index].stamp = self->pointer_stamp; xrdp_wm_send_pointer(self->wm, index, self->pointer_items[index].data, self->pointer_items[index].mask, self->pointer_items[index].x, self->pointer_items[index].y); self->wm->current_pointer = index; DEBUG(("adding pointer at %d", index)); return index; } /*****************************************************************************/ /* this does not take owership of brush_item_data, it makes a copy */ int APP_CC xrdp_cache_add_brush(struct xrdp_cache* self, char* brush_item_data) { int i; int oldest; int index; if (self == 0) { return 0; } self->brush_stamp++; /* look for match */ for (i = 0; i < 64; i++) { if (g_memcmp(self->brush_items[i].pattern, brush_item_data, 8) == 0) { self->brush_items[i].stamp = self->brush_stamp; DEBUG(("found brush at %d", i)); return i; } } /* look for oldest */ index = 0; oldest = 0x7fffffff; for (i = 0; i < 64; i++) { if (self->brush_items[i].stamp < oldest) { oldest = self->brush_items[i].stamp; index = i; } } g_memcpy(self->brush_items[index].pattern, brush_item_data, 8); self->brush_items[index].stamp = self->brush_stamp; libxrdp_orders_send_brush(self->session, 8, 8, 1, 0x81, 8, self->brush_items[index].pattern, index); DEBUG(("adding brush at %d", index)); return index; } xrdp-0.6.0/xrdp/xrdp_font.c000066400000000000000000000120231203155130500156070ustar00rootroot00000000000000 /* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2004-2010 fonts */ /* The fv1 files contain Font File Header (just one) FNT1 4 bytes Font Name 32 bytes Font Size 2 bytes Font Style 2 bytes Pad 8 bytes Font Data (repeats) Width 2 bytes Height 2 bytes Baseline 2 bytes Offset 2 bytes Incby 2 bytes Pad 6 bytes Glyph Data var, see FONT_DATASIZE macro */ #include "xrdp.h" #if 0 /* not used */ static char w_char[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x20, 0x80, 0x08, 0x50, 0x80, 0x04, 0x51, 0x00, 0x04, 0x51, 0x00, 0x04, 0x51, 0x00, 0x02, 0x8a, 0x00, 0x02, 0x8a, 0x00, 0x02, 0x8a, 0x00, 0x01, 0x04, 0x00, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; #endif /*****************************************************************************/ struct xrdp_font* APP_CC xrdp_font_create(struct xrdp_wm* wm) { struct xrdp_font* self; struct stream* s; int fd; int b; int i; int index; int datasize; int file_size; struct xrdp_font_char* f; char file_path[256]; DEBUG(("in xrdp_font_create")); g_snprintf(file_path, 255, "%s/%s", XRDP_SHARE_PATH, DEFAULT_FONT_NAME); if (!g_file_exist(file_path)) { g_writeln("xrdp_font_create: error font file [%s] does not exist", file_path); return 0; } file_size = g_file_get_size(file_path); if (file_size < 1) { g_writeln("xrdp_font_create: error reading font from file [%s]", file_path); return 0; } self = (struct xrdp_font*)g_malloc(sizeof(struct xrdp_font), 1); self->wm = wm; make_stream(s); init_stream(s, file_size + 1024); fd = g_file_open(file_path); if (fd != -1) { b = g_file_read(fd, s->data, file_size + 1024); g_file_close(fd); if (b > 0) { s->end = s->data + b; in_uint8s(s, 4); in_uint8a(s, self->name, 32); in_uint16_le(s, self->size); in_uint16_le(s, self->style); in_uint8s(s, 8); index = 32; while (s_check_rem(s, 16)) { f = self->font_items + index; in_sint16_le(s, i); f->width = i; in_sint16_le(s, i); f->height = i; in_sint16_le(s, i); f->baseline = i; in_sint16_le(s, i); f->offset = i; in_sint16_le(s, i); f->incby = i; in_uint8s(s, 6); datasize = FONT_DATASIZE(f); if (datasize < 0 || datasize > 512) { /* shouldn't happen */ g_writeln("error in xrdp_font_create, datasize wrong"); g_writeln("width %d height %d datasize %d index %d", f->width, f->height, datasize, index); break; } if (s_check_rem(s, datasize)) { f->data = (char*)g_malloc(datasize, 0); in_uint8a(s, f->data, datasize); } else { g_writeln("error in xrdp_font_create"); } index++; } } } free_stream(s); /* self->font_items[0].offset = -4; self->font_items[0].baseline = -16; self->font_items[0].width = 24; self->font_items[0].height = 16; self->font_items[0].data = g_malloc(3 * 16, 0); g_memcpy(self->font_items[0].data, w_char, 3 * 16); */ DEBUG(("out xrdp_font_create")); return self; } /*****************************************************************************/ /* free the font and all the items */ void APP_CC xrdp_font_delete(struct xrdp_font* self) { int i; if (self == 0) { return; } for (i = 0; i < NUM_FONTS; i++) { g_free(self->font_items[i].data); } g_free(self); } /*****************************************************************************/ /* compare the two font items returns 1 if they match */ int APP_CC xrdp_font_item_compare(struct xrdp_font_char* font1, struct xrdp_font_char* font2) { int datasize; if (font1 == 0) { return 0; } if (font2 == 0) { return 0; } if (font1->offset != font2->offset) { return 0; } if (font1->baseline != font2->baseline) { return 0; } if (font1->width != font2->width) { return 0; } if (font1->height != font2->height) { return 0; } datasize = FONT_DATASIZE(font1); if (g_memcmp(font1->data, font2->data, datasize) == 0) { return 1; } return 0; } xrdp-0.6.0/xrdp/xrdp_listen.c000066400000000000000000000210351203155130500161420ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2004-2010 listen for incoming connection */ #include "xrdp.h" /* 'g_process' is protected by the semaphore 'g_process_sem'. One thread sets g_process and waits for the other to process it */ static tbus g_process_sem = 0; static struct xrdp_process* g_process = 0; /*****************************************************************************/ struct xrdp_listen* APP_CC xrdp_listen_create(void) { struct xrdp_listen* self; int pid; char text[256]; pid = g_getpid(); self = (struct xrdp_listen*)g_malloc(sizeof(struct xrdp_listen), 1); g_snprintf(text, 255, "xrdp_%8.8x_listen_pro_done_event", pid); self->pro_done_event = g_create_wait_obj(text); self->process_list = list_create(); if (g_process_sem == 0) { g_process_sem = tc_sem_create(0); } self->listen_trans = trans_create(TRANS_MODE_TCP, 16, 16); if (self->listen_trans == 0) { g_writeln("xrdp_listen_create: trans_create failed"); } return self; } /*****************************************************************************/ void APP_CC xrdp_listen_delete(struct xrdp_listen* self) { if (self->listen_trans != 0) { trans_delete(self->listen_trans); } if (g_process_sem != 0) { tc_sem_delete(g_process_sem); g_process_sem = 0; } g_delete_wait_obj(self->pro_done_event); list_delete(self->process_list); g_free(self); } /*****************************************************************************/ /* returns error */ static int APP_CC xrdp_listen_add_pro(struct xrdp_listen* self, struct xrdp_process* process) { list_add_item(self->process_list, (tbus)process); return 0; } /*****************************************************************************/ static int APP_CC xrdp_listen_delete_done_pro(struct xrdp_listen* self) { int i; struct xrdp_process* pro; for (i = self->process_list->count - 1; i >= 0; i--) { pro = (struct xrdp_process*)list_get_item(self->process_list, i); if (pro != 0) { if (pro->status < 0) { xrdp_process_delete(pro); list_remove_item(self->process_list, i); } } } return 0; } /*****************************************************************************/ /* i can't get stupid in_val to work, hum using global var for now */ THREAD_RV THREAD_CC xrdp_process_run(void* in_val) { struct xrdp_process* process; DEBUG(("process started")); process = g_process; g_process = 0; tc_sem_inc(g_process_sem); xrdp_process_main_loop(process); DEBUG(("process done")); return 0; } /*****************************************************************************/ static int xrdp_listen_get_port_address(char* port, int port_bytes, char* address, int address_bytes, struct xrdp_startup_params* startup_param) { int fd; int error; int index; char* val; struct list* names; struct list* values; char cfg_file[256]; /* default to port 3389 */ g_strncpy(port, "3389", port_bytes - 1); /* Default to all */ g_strncpy(address, "0.0.0.0", address_bytes - 1); /* see if port or address is in xrdp.ini file */ g_snprintf(cfg_file, 255, "%s/xrdp.ini", XRDP_CFG_PATH); fd = g_file_open(cfg_file); if (fd > 0) { names = list_create(); names->auto_free = 1; values = list_create(); values->auto_free = 1; if (file_read_section(fd, "globals", names, values) == 0) { for (index = 0; index < names->count; index++) { val = (char*)list_get_item(names, index); if (val != 0) { if (g_strcasecmp(val, "port") == 0) { val = (char*)list_get_item(values, index); error = g_atoi(val); if ((error > 0) && (error < 65000)) { g_strncpy(port, val, port_bytes - 1); } } if (g_strcasecmp(val, "address") == 0) { val = (char*)list_get_item(values, index); g_strncpy(address, val, address_bytes - 1); } } } } list_delete(names); list_delete(values); g_file_close(fd); } /* startup_param overrides */ if (startup_param->port[0] != 0) { g_strncpy(port, startup_param->port, port_bytes - 1); } return 0; } /*****************************************************************************/ /* a new connection is coming in */ int DEFAULT_CC xrdp_listen_conn_in(struct trans* self, struct trans* new_self) { struct xrdp_process* process; struct xrdp_listen* lis; lis = (struct xrdp_listen*)(self->callback_data); process = xrdp_process_create(lis, lis->pro_done_event); if (xrdp_listen_add_pro(lis, process) == 0) { /* start thread */ process->server_trans = new_self; g_process = process; tc_thread_create(xrdp_process_run, 0); tc_sem_dec(g_process_sem); /* this will wait */ } else { xrdp_process_delete(process); } return 0; } /*****************************************************************************/ /* wait for incoming connections */ int APP_CC xrdp_listen_main_loop(struct xrdp_listen* self, struct xrdp_startup_params* startup_param) { int error; int robjs_count; int cont; int timeout = 0; char port[128]; char address[256]; tbus robjs[8]; tbus term_obj; tbus sync_obj; tbus sck_obj; tbus done_obj; self->status = 1; if (xrdp_listen_get_port_address(port, sizeof(port), address, sizeof(address), startup_param) != 0) { g_writeln("xrdp_listen_main_loop: xrdp_listen_get_port failed"); self->status = -1; return 1; } error = trans_listen_address(self->listen_trans, port, address); if (error == 0) { self->listen_trans->trans_conn_in = xrdp_listen_conn_in; self->listen_trans->callback_data = self; term_obj = g_get_term_event(); sync_obj = g_get_sync_event(); done_obj = self->pro_done_event; cont = 1; while (cont) { /* build the wait obj list */ robjs_count = 0; robjs[robjs_count++] = term_obj; robjs[robjs_count++] = sync_obj; robjs[robjs_count++] = done_obj; timeout = -1; if (trans_get_wait_objs(self->listen_trans, robjs, &robjs_count, &timeout) != 0) { break; } /* wait */ if (g_obj_wait(robjs, robjs_count, 0, 0, timeout) != 0) { /* error, should not get here */ g_sleep(100); } if (g_is_wait_obj_set(term_obj)) /* term */ { break; } if (g_is_wait_obj_set(sync_obj)) /* sync */ { g_reset_wait_obj(sync_obj); g_loop(); } if (g_is_wait_obj_set(done_obj)) /* pro_done_event */ { g_reset_wait_obj(done_obj); xrdp_listen_delete_done_pro(self); } if (trans_check_wait_objs(self->listen_trans) != 0) { break; } } /* stop listening */ trans_delete(self->listen_trans); self->listen_trans = 0; /* second loop to wait for all process threads to close */ cont = 1; while (cont) { if (self->process_list->count == 0) { break; } /* build the wait obj list */ robjs_count = 0; robjs[robjs_count++] = sync_obj; robjs[robjs_count++] = done_obj; /* wait */ if (g_obj_wait(robjs, robjs_count, 0, 0, -1) != 0) { /* error, should not get here */ g_sleep(100); } if (g_is_wait_obj_set(sync_obj)) /* sync */ { g_reset_wait_obj(sync_obj); g_loop(); } if (g_is_wait_obj_set(done_obj)) /* pro_done_event */ { g_reset_wait_obj(done_obj); xrdp_listen_delete_done_pro(self); } } } else { g_writeln("xrdp_listen_main_loop: listen error, possible port " "already in use"); } self->status = -1; return 0; } xrdp-0.6.0/xrdp/xrdp_login_wnd.c000066400000000000000000000434521203155130500166330ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2004-2010 main login window and login help window */ #include "xrdp.h" /*****************************************************************************/ /* all login help screen events go here */ static int DEFAULT_CC xrdp_wm_login_help_notify(struct xrdp_bitmap* wnd, struct xrdp_bitmap* sender, int msg, long param1, long param2) { struct xrdp_painter* p; if (wnd == 0) { return 0; } if (sender == 0) { return 0; } if (wnd->owner == 0) { return 0; } if (msg == 1) /* click */ { if (sender->id == 1) /* ok button */ { if (sender->owner->notify != 0) { wnd->owner->notify(wnd->owner, wnd, 100, 1, 0); /* ok */ } } } else if (msg == WM_PAINT) /* 3 */ { p = (struct xrdp_painter*)param1; if (p != 0) { p->fg_color = wnd->wm->black; xrdp_painter_draw_text(p, wnd, 10, 30, "You must be authenticated \ before using this"); xrdp_painter_draw_text(p, wnd, 10, 46, "session."); xrdp_painter_draw_text(p, wnd, 10, 78, "Enter a valid username in \ the username edit box."); xrdp_painter_draw_text(p, wnd, 10, 94, "Enter the password in \ the password edit box."); xrdp_painter_draw_text(p, wnd, 10, 110, "Both the username and \ password are case"); xrdp_painter_draw_text(p, wnd, 10, 126, "sensitive."); xrdp_painter_draw_text(p, wnd, 10, 158, "Contact your system \ administrator if you are"); xrdp_painter_draw_text(p, wnd, 10, 174, "having problems \ logging on."); } } return 0; } #if 0 /*****************************************************************************/ static int DEFAULT_CC xrdp_wm_popup_notify(struct xrdp_bitmap* wnd, struct xrdp_bitmap* sender, int msg, int param1, int param2) { return 0; } #endif /*****************************************************************************/ int APP_CC xrdp_wm_delete_all_childs(struct xrdp_wm* self) { int index; struct xrdp_bitmap* b; struct xrdp_rect rect; for (index = self->screen->child_list->count - 1; index >= 0; index--) { b = (struct xrdp_bitmap*)list_get_item(self->screen->child_list, index); MAKERECT(rect, b->left, b->top, b->width, b->height); xrdp_bitmap_delete(b); xrdp_bitmap_invalidate(self->screen, &rect); } return 0; } /*****************************************************************************/ static int APP_CC set_mod_data_item(struct xrdp_mod_data* mod, char* name, char* value) { int index; for (index = 0; index < mod->names->count; index++) { if (g_strncmp(name, (char*)list_get_item(mod->names, index), 255) == 0) { list_remove_item(mod->values, index); list_insert_item(mod->values, index, (long)g_strdup(value)); } } return 0; } /*****************************************************************************/ static int APP_CC xrdp_wm_help_clicked(struct xrdp_bitmap* wnd) { struct xrdp_bitmap* help; struct xrdp_bitmap* but; /* create help screen */ help = xrdp_bitmap_create(DEFAULT_WND_HELP_W, DEFAULT_WND_HELP_H, wnd->wm->screen->bpp, WND_TYPE_WND, wnd->wm); list_insert_item(wnd->wm->screen->child_list, 0, (long)help); help->parent = wnd->wm->screen; help->owner = wnd; wnd->modal_dialog = help; help->bg_color = wnd->wm->grey; help->left = wnd->wm->screen->width / 2 - help->width / 2; help->top = wnd->wm->screen->height / 2 - help->height / 2; help->notify = xrdp_wm_login_help_notify; set_string(&help->caption1, "Login help"); /* ok button */ but = xrdp_bitmap_create(DEFAULT_BUTTON_W, DEFAULT_BUTTON_H, wnd->wm->screen->bpp, WND_TYPE_BUTTON, wnd->wm); list_insert_item(help->child_list, 0, (long)but); but->parent = help; but->owner = help; but->left = ((DEFAULT_WND_HELP_W / 2) - (DEFAULT_BUTTON_W / 2)); /* center */ but->top = DEFAULT_WND_HELP_H - DEFAULT_BUTTON_H - 15; but->id = 1; but->tab_stop = 1; set_string(&but->caption1, "OK"); /* draw it */ help->focused_control = but; help->default_button = but; help->esc_button = but; xrdp_bitmap_invalidate(help, 0); xrdp_wm_set_focused(wnd->wm, help); return 0; } /*****************************************************************************/ static int APP_CC xrdp_wm_cancel_clicked(struct xrdp_bitmap* wnd) { if (wnd != 0) { if (wnd->wm != 0) { if (wnd->wm->pro_layer != 0) { g_set_wait_obj(wnd->wm->pro_layer->self_term_event); } } } return 0; } /*****************************************************************************/ static int APP_CC xrdp_wm_ok_clicked(struct xrdp_bitmap* wnd) { struct xrdp_bitmap* combo; struct xrdp_bitmap* label; struct xrdp_bitmap* edit; struct xrdp_wm* wm; struct xrdp_mod_data* mod_data; int i; wm = wnd->wm; combo = xrdp_bitmap_get_child_by_id(wnd, 6); if (combo != 0) { mod_data = (struct xrdp_mod_data*) list_get_item(combo->data_list, combo->item_index); if (mod_data != 0) { /* get the user typed values */ i = 100; label = xrdp_bitmap_get_child_by_id(wnd, i); edit = xrdp_bitmap_get_child_by_id(wnd, i + 1); while (label != 0 && edit != 0) { set_mod_data_item(mod_data, label->caption1, edit->caption1); i += 2; label = xrdp_bitmap_get_child_by_id(wnd, i); edit = xrdp_bitmap_get_child_by_id(wnd, i + 1); } list_delete(wm->mm->login_names); list_delete(wm->mm->login_values); wm->mm->login_names = list_create(); wm->mm->login_names->auto_free = 1; wm->mm->login_values = list_create(); wm->mm->login_values->auto_free = 1; /* gota copy these cause dialog gets freed */ list_append_list_strdup(mod_data->names, wm->mm->login_names, 0); list_append_list_strdup(mod_data->values, wm->mm->login_values, 0); xrdp_wm_set_login_mode(wm, 2); } } return 0; } /******************************************************************************/ static int APP_CC xrdp_wm_show_edits(struct xrdp_wm* self, struct xrdp_bitmap* combo) { int count; int index; int insert_index; int username_set; char* name; char* value; struct xrdp_mod_data* mod; struct xrdp_bitmap* b; username_set = 0; /* free labels and edits, cause we gota create them */ /* creation or combo changed */ for (index = 100; index < 200; index++) { b = xrdp_bitmap_get_child_by_id(combo->parent, index); xrdp_bitmap_delete(b); } insert_index = list_index_of(self->login_window->child_list, (long)combo); insert_index++; mod = (struct xrdp_mod_data*) list_get_item(combo->data_list, combo->item_index); if (mod != 0) { count = 0; for (index = 0; index < mod->names->count; index++) { value = (char*)list_get_item(mod->values, index); if (g_strncmp("ask", value, 3) == 0) { /* label */ b = xrdp_bitmap_create(70, DEFAULT_EDIT_H, self->screen->bpp, WND_TYPE_LABEL, self); list_insert_item(self->login_window->child_list, insert_index, (long)b); insert_index++; b->parent = self->login_window; b->owner = self->login_window; b->left = self->login_window->width >= DEFAULT_WND_LOGIN_W ? 155 : 5; b->top = DEFAULT_ELEMENT_TOP + DEFAULT_COMBO_H + 5 + (DEFAULT_EDIT_H+5) * count; b->id = 100 + 2 * count; name = (char*)list_get_item(mod->names, index); set_string(&b->caption1, name); /* edit */ b = xrdp_bitmap_create(DEFAULT_EDIT_W, DEFAULT_EDIT_H, self->screen->bpp, WND_TYPE_EDIT, self); list_insert_item(self->login_window->child_list, insert_index, (long)b); insert_index++; b->parent = self->login_window; b->owner = self->login_window; b->left = self->login_window->width >= DEFAULT_WND_LOGIN_W ? DEFAULT_WND_LOGIN_W - DEFAULT_EDIT_W - 30 : 70; b->top = DEFAULT_ELEMENT_TOP + DEFAULT_COMBO_H + 5 + (DEFAULT_EDIT_H+5) * count; b->id = 100 + 2 * count + 1; b->pointer = 1; b->tab_stop = 1; b->caption1 = (char*)g_malloc(256, 1); g_strncpy(b->caption1, value + 3, 255); b->edit_pos = g_mbstowcs(0, b->caption1, 0); if (self->login_window->focused_control == 0) { self->login_window->focused_control = b; } if (g_strncmp(name, "username", 255) == 0) { g_strncpy(b->caption1, self->session->client_info->username, 255); b->edit_pos = g_mbstowcs(0, b->caption1, 0); if (b->edit_pos > 0) { username_set = 1; } } if (g_strncmp(name, "password", 255) == 0) { b->password_char = '*'; if (username_set) { if (b->parent != 0) { b->parent->focused_control = b; } } } count++; } } } return 0; } /*****************************************************************************/ /* all login screen events go here */ static int DEFAULT_CC xrdp_wm_login_notify(struct xrdp_bitmap* wnd, struct xrdp_bitmap* sender, int msg, long param1, long param2) { struct xrdp_bitmap* b; struct xrdp_rect rect; int i; if (wnd->modal_dialog != 0 && msg != 100) { return 0; } if (msg == 1) /* click */ { if (sender->id == 1) /* help button */ { xrdp_wm_help_clicked(wnd); } else if (sender->id == 2) /* cancel button */ { xrdp_wm_cancel_clicked(wnd); } else if (sender->id == 3) /* ok button */ { xrdp_wm_ok_clicked(wnd); } } else if (msg == 2) /* mouse move */ { } else if (msg == 100) /* modal result is done */ { i = list_index_of(wnd->wm->screen->child_list, (long)sender); if (i >= 0) { b = (struct xrdp_bitmap*) list_get_item(wnd->wm->screen->child_list, i); list_remove_item(sender->wm->screen->child_list, i); MAKERECT(rect, b->left, b->top, b->width, b->height); xrdp_bitmap_invalidate(wnd->wm->screen, &rect); xrdp_bitmap_delete(sender); wnd->modal_dialog = 0; xrdp_wm_set_focused(wnd->wm, wnd); } } else if (msg == CB_ITEMCHANGE) /* combo box change */ { xrdp_wm_show_edits(wnd->wm, sender); xrdp_bitmap_invalidate(wnd, 0); /* invalidate the whole dialog for now */ } return 0; } /******************************************************************************/ static int APP_CC xrdp_wm_login_fill_in_combo(struct xrdp_wm* self, struct xrdp_bitmap* b) { struct list* sections; struct list* section_names; struct list* section_values; int fd; int i; int j; char* p; char* q; char* r; char name[256]; char cfg_file[256]; struct xrdp_mod_data* mod_data; sections = list_create(); sections->auto_free = 1; section_names = list_create(); section_names->auto_free = 1; section_values = list_create(); section_values->auto_free = 1; g_snprintf(cfg_file, 255, "%s/xrdp.ini", XRDP_CFG_PATH); fd = g_file_open(cfg_file); /* xrdp.ini */ if (fd < 1) { g_writeln("Could not read xrdp ini file %s", cfg_file); } file_read_sections(fd, sections); for (i = 0; i < sections->count; i++) { p = (char*)list_get_item(sections, i); file_read_section(fd, p, section_names, section_values); if (g_strncmp(p, "globals", 255) == 0) { } else { g_strncpy(name, p, 255); mod_data = (struct xrdp_mod_data*) g_malloc(sizeof(struct xrdp_mod_data), 1); mod_data->names = list_create(); mod_data->names->auto_free = 1; mod_data->values = list_create(); mod_data->values->auto_free = 1; for (j = 0; j < section_names->count; j++) { q = (char*)list_get_item(section_names, j); r = (char*)list_get_item(section_values, j); if (g_strncmp("name", q, 255) == 0) { g_strncpy(name, r, 255); } list_add_item(mod_data->names, (long)g_strdup(q)); list_add_item(mod_data->values, (long)g_strdup(r)); } list_add_item(b->string_list, (long)g_strdup(name)); list_add_item(b->data_list, (long)mod_data); } } g_file_close(fd); list_delete(sections); list_delete(section_names); list_delete(section_values); return 0; } /******************************************************************************/ int APP_CC xrdp_login_wnd_create(struct xrdp_wm* self) { struct xrdp_bitmap* but; struct xrdp_bitmap* combo; char file_path[256]; int log_width; int log_height; int regular; log_width = DEFAULT_WND_LOGIN_W; log_height = DEFAULT_WND_LOGIN_H; regular = 1; if (self->screen->width < log_width) { if (self->screen->width < 240) { log_width = self->screen->width - 4; } else { log_width = 240; } regular = 0; } /* draw login window */ self->login_window = xrdp_bitmap_create(log_width, log_height, self->screen->bpp, WND_TYPE_WND, self); list_add_item(self->screen->child_list, (long)self->login_window); self->login_window->parent = self->screen; self->login_window->owner = self->screen; self->login_window->bg_color = self->grey; self->login_window->left = self->screen->width / 2 - self->login_window->width / 2; self->login_window->top = self->screen->height / 2 - self->login_window->height / 2; self->login_window->notify = xrdp_wm_login_notify; set_string(&self->login_window->caption1, "Login to xrdp"); if (regular) { /* image */ but = xrdp_bitmap_create(4, 4, self->screen->bpp, WND_TYPE_IMAGE, self); if (self->screen->bpp > 8) { g_snprintf(file_path, 255, "%s/xrdp24b.bmp", XRDP_SHARE_PATH); } else { g_snprintf(file_path, 255, "%s/xrdp256.bmp", XRDP_SHARE_PATH); } xrdp_bitmap_load(but, file_path, self->palette); but->parent = self->screen; but->owner = self->screen; but->left = self->screen->width - but->width; but->top = self->screen->height - but->height; list_add_item(self->screen->child_list, (long)but); /* image */ but = xrdp_bitmap_create(4, 4, self->screen->bpp, WND_TYPE_IMAGE, self); if (self->screen->bpp > 8) { g_snprintf(file_path, 255, "%s/ad24b.bmp", XRDP_SHARE_PATH); } else { g_snprintf(file_path, 255, "%s/ad256.bmp", XRDP_SHARE_PATH); } xrdp_bitmap_load(but, file_path, self->palette); but->parent = self->login_window; but->owner = self->login_window; but->left = 10; but->top = 30; list_add_item(self->login_window->child_list, (long)but); } /* label */ but = xrdp_bitmap_create(60, DEFAULT_EDIT_H, self->screen->bpp, WND_TYPE_LABEL, self); list_add_item(self->login_window->child_list, (long)but); but->parent = self->login_window; but->owner = self->login_window; but->left = regular ? 155 : 5; but->top = DEFAULT_ELEMENT_TOP; set_string(&but->caption1, "Module"); /* combo */ combo = xrdp_bitmap_create(DEFAULT_COMBO_W, DEFAULT_COMBO_H, self->screen->bpp, WND_TYPE_COMBO, self); list_add_item(self->login_window->child_list, (long)combo); combo->parent = self->login_window; combo->owner = self->login_window; combo->left = regular ? DEFAULT_WND_LOGIN_W - DEFAULT_COMBO_W - 30 : 70; combo->top = DEFAULT_ELEMENT_TOP; combo->id = 6; combo->tab_stop = 1; xrdp_wm_login_fill_in_combo(self, combo); /* button */ but = xrdp_bitmap_create(DEFAULT_BUTTON_W, DEFAULT_BUTTON_H, self->screen->bpp, WND_TYPE_BUTTON, self); list_add_item(self->login_window->child_list, (long)but); but->parent = self->login_window; but->owner = self->login_window; but->left = regular ? DEFAULT_WND_LOGIN_W - ((DEFAULT_BUTTON_W+10)*3) - 10 : 30; but->top = DEFAULT_WND_LOGIN_H - DEFAULT_BUTTON_H - 15; but->id = 3; set_string(&but->caption1, "OK"); but->tab_stop = 1; self->login_window->default_button = but; /* button */ but = xrdp_bitmap_create(DEFAULT_BUTTON_W, DEFAULT_BUTTON_H, self->screen->bpp, WND_TYPE_BUTTON, self); list_add_item(self->login_window->child_list, (long)but); but->parent = self->login_window; but->owner = self->login_window; but->left = regular ? DEFAULT_WND_LOGIN_W - ((DEFAULT_BUTTON_W+10)*2) - 10 : ((log_width - 30) - DEFAULT_BUTTON_W); but->top = DEFAULT_WND_LOGIN_H - DEFAULT_BUTTON_H - 15; but->id = 2; set_string(&but->caption1, "Cancel"); but->tab_stop = 1; self->login_window->esc_button = but; if (regular) { /* button */ but = xrdp_bitmap_create(DEFAULT_BUTTON_W, DEFAULT_BUTTON_H, self->screen->bpp, WND_TYPE_BUTTON, self); list_add_item(self->login_window->child_list, (long)but); but->parent = self->login_window; but->owner = self->login_window; but->left = DEFAULT_WND_LOGIN_W - (DEFAULT_BUTTON_W+10) - 10; but->top = DEFAULT_WND_LOGIN_H - DEFAULT_BUTTON_H - 15; but->id = 1; set_string(&but->caption1, "Help"); but->tab_stop = 1; } /* labels and edits */ xrdp_wm_show_edits(self, combo); return 0; } xrdp-0.6.0/xrdp/xrdp_mm.c000066400000000000000000001142631203155130500152630ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2004-2010 module manager */ #include "xrdp.h" /*****************************************************************************/ struct xrdp_mm* APP_CC xrdp_mm_create(struct xrdp_wm* owner) { struct xrdp_mm* self; self = (struct xrdp_mm*)g_malloc(sizeof(struct xrdp_mm), 1); self->wm = owner; self->login_names = list_create(); self->login_names->auto_free = 1; self->login_values = list_create(); self->login_values->auto_free = 1; return self; } /*****************************************************************************/ /* called from main thread */ static long DEFAULT_CC xrdp_mm_sync_unload(long param1, long param2) { return g_free_library(param1); } /*****************************************************************************/ /* called from main thread */ static long DEFAULT_CC xrdp_mm_sync_load(long param1, long param2) { long rv; char* libname; libname = (char*)param1; rv = g_load_library(libname); return rv; } /*****************************************************************************/ static void APP_CC xrdp_mm_module_cleanup(struct xrdp_mm* self) { if (self->mod != 0) { if (self->mod_exit != 0) { /* let the module cleanup */ self->mod_exit(self->mod); } } if (self->mod_handle != 0) { /* main thread unload */ g_xrdp_sync(xrdp_mm_sync_unload, self->mod_handle, 0); } trans_delete(self->chan_trans); self->chan_trans = 0; self->chan_trans_up = 0; self->mod_init = 0; self->mod_exit = 0; self->mod = 0; self->mod_handle = 0; } /*****************************************************************************/ void APP_CC xrdp_mm_delete(struct xrdp_mm* self) { if (self == 0) { return; } /* free any module stuff */ xrdp_mm_module_cleanup(self); trans_delete(self->sesman_trans); self->sesman_trans = 0; self->sesman_trans_up = 0; list_delete(self->login_names); list_delete(self->login_values); g_free(self); } /*****************************************************************************/ static int APP_CC xrdp_mm_send_login(struct xrdp_mm* self) { struct stream* s; int rv; int index; int count; int xserverbpp; char* username; char* password; char* name; char* value; xrdp_wm_log_msg(self->wm, "sending login info to session manager, " "please wait..."); username = 0; password = 0; self->code = 0; xserverbpp = 0; count = self->login_names->count; for (index = 0; index < count; index++) { name = (char*)list_get_item(self->login_names, index); value = (char*)list_get_item(self->login_values, index); if (g_strcasecmp(name, "username") == 0) { username = value; } else if (g_strcasecmp(name, "password") == 0) { password = value; } else if (g_strcasecmp(name, "lib") == 0) { if ((g_strcasecmp(value, "libxup.so") == 0) || (g_strcasecmp(value, "xup.dll") == 0)) { self->code = 10; } } else if (g_strcasecmp(name, "xserverbpp") == 0) { xserverbpp = g_atoi(value); } } if ((username == 0) || (password == 0)) { xrdp_wm_log_msg(self->wm, "Error finding username and password"); return 1; } s = trans_get_out_s(self->sesman_trans, 8192); s_push_layer(s, channel_hdr, 8); /* this code is either 0 for Xvnc or 10 for X11rdp */ out_uint16_be(s, self->code); index = g_strlen(username); out_uint16_be(s, index); out_uint8a(s, username, index); index = g_strlen(password); out_uint16_be(s, index); out_uint8a(s, password, index); out_uint16_be(s, self->wm->screen->width); out_uint16_be(s, self->wm->screen->height); if (xserverbpp > 0) { out_uint16_be(s, xserverbpp); } else { out_uint16_be(s, self->wm->screen->bpp); } /* send domain */ index = g_strlen(self->wm->client_info->domain); out_uint16_be(s, index); out_uint8a(s, self->wm->client_info->domain, index); /* send program / shell */ index = g_strlen(self->wm->client_info->program); out_uint16_be(s, index); out_uint8a(s, self->wm->client_info->program, index); /* send directory */ index = g_strlen(self->wm->client_info->directory); out_uint16_be(s, index); out_uint8a(s, self->wm->client_info->directory, index); /* send client ip */ index = g_strlen(self->wm->client_info->client_ip); out_uint16_be(s, index); out_uint8a(s, self->wm->client_info->client_ip, index); s_mark_end(s); s_pop_layer(s, channel_hdr); out_uint32_be(s, 0); /* version */ index = (int)(s->end - s->data); out_uint32_be(s, index); /* size */ rv = trans_force_write(self->sesman_trans); if (rv != 0) { xrdp_wm_log_msg(self->wm, "xrdp_mm_send_login: xrdp_mm_send_login failed"); } return rv; } /*****************************************************************************/ /* returns error */ /* this goes through the login_names looking for one called 'aname' then it copies the corisponding login_values item into 'dest' 'dest' must be at least 'dest_len' + 1 bytes in size */ static int APP_CC xrdp_mm_get_value(struct xrdp_mm* self, char* aname, char* dest, int dest_len) { char* name; char* value; int index; int count; int rv; rv = 1; /* find the library name */ dest[0] = 0; count = self->login_names->count; for (index = 0; index < count; index++) { name = (char*)list_get_item(self->login_names, index); value = (char*)list_get_item(self->login_values, index); if ((name == 0) || (value == 0)) { break; } if (g_strcasecmp(name, aname) == 0) { g_strncpy(dest, value, dest_len); rv = 0; } } return rv; } /*****************************************************************************/ static int APP_CC xrdp_mm_setup_mod1(struct xrdp_mm* self) { void* func; char lib[256]; char text[256]; if (self == 0) { return 1; } lib[0] = 0; if (xrdp_mm_get_value(self, "lib", lib, 255) != 0) { g_snprintf(text, 255, "no library name specified in xrdp.ini, please add " "lib=libxrdp-vnc.so or similar"); xrdp_wm_log_msg(self->wm, text); return 1; } if (lib[0] == 0) { g_snprintf(text, 255, "empty library name specified in xrdp.ini, please " "add lib=libxrdp-vnc.so or similar"); xrdp_wm_log_msg(self->wm, text); return 1; } if (self->mod_handle == 0) { self->mod_handle = g_xrdp_sync(xrdp_mm_sync_load, (long)lib, 0); if (self->mod_handle != 0) { func = g_get_proc_address(self->mod_handle, "mod_init"); if (func == 0) { func = g_get_proc_address(self->mod_handle, "_mod_init"); } if (func == 0) { g_snprintf(text, 255, "error finding proc mod_init in %s, not a valid " "xrdp backend", lib); xrdp_wm_log_msg(self->wm, text); } self->mod_init = (struct xrdp_mod* (*)(void))func; func = g_get_proc_address(self->mod_handle, "mod_exit"); if (func == 0) { func = g_get_proc_address(self->mod_handle, "_mod_exit"); } if (func == 0) { g_snprintf(text, 255, "error finding proc mod_exit in %s, not a valid " "xrdp backend", lib); xrdp_wm_log_msg(self->wm, text); } self->mod_exit = (int (*)(struct xrdp_mod*))func; if ((self->mod_init != 0) && (self->mod_exit != 0)) { self->mod = self->mod_init(); if (self->mod != 0) { g_writeln("loaded module '%s' ok, interface size %d, version %d", lib, self->mod->size, self->mod->version); } } } else { g_snprintf(text, 255, "error loading %s specified in xrdp.ini, please " "add a valid entry like lib=libxrdp-vnc.so or similar", lib); xrdp_wm_log_msg(self->wm, text); } if (self->mod != 0) { self->mod->wm = (long)(self->wm); self->mod->server_begin_update = server_begin_update; self->mod->server_end_update = server_end_update; self->mod->server_bell_trigger = server_bell_trigger; self->mod->server_fill_rect = server_fill_rect; self->mod->server_screen_blt = server_screen_blt; self->mod->server_paint_rect = server_paint_rect; self->mod->server_set_pointer = server_set_pointer; self->mod->server_palette = server_palette; self->mod->server_msg = server_msg; self->mod->server_is_term = server_is_term; self->mod->server_set_clip = server_set_clip; self->mod->server_reset_clip = server_reset_clip; self->mod->server_set_fgcolor = server_set_fgcolor; self->mod->server_set_bgcolor = server_set_bgcolor; self->mod->server_set_opcode = server_set_opcode; self->mod->server_set_mixmode = server_set_mixmode; self->mod->server_set_brush = server_set_brush; self->mod->server_set_pen = server_set_pen; self->mod->server_draw_line = server_draw_line; self->mod->server_add_char = server_add_char; self->mod->server_draw_text = server_draw_text; self->mod->server_reset = server_reset; self->mod->server_query_channel = server_query_channel; self->mod->server_get_channel_id = server_get_channel_id; self->mod->server_send_to_channel = server_send_to_channel; } } /* id self->mod is null, there must be a problem */ if (self->mod == 0) { DEBUG(("problem loading lib in xrdp_mm_setup_mod1")); return 1; } return 0; } /*****************************************************************************/ static int APP_CC xrdp_mm_setup_mod2(struct xrdp_mm* self) { char text[256]; char* name; char* value; int i; int rv; int key_flags; int device_flags; g_memset(text,0,sizeof(char) * 256); rv = 1; text[0] = 0; if (!g_is_wait_obj_set(self->wm->pro_layer->self_term_event)) { if (self->mod->mod_start(self->mod, self->wm->screen->width, self->wm->screen->height, self->wm->screen->bpp) != 0) { g_set_wait_obj(self->wm->pro_layer->self_term_event); /* kill session */ } } if (!g_is_wait_obj_set(self->wm->pro_layer->self_term_event)) { if (self->display > 0) { if (self->code == 0) /* Xvnc */ { g_snprintf(text, 255, "%d", 5900 + self->display); } else if (self->code == 10) /* X11rdp */ { g_snprintf(text, 255, "%d", 6200 + self->display); } else { g_set_wait_obj(self->wm->pro_layer->self_term_event); /* kill session */ } } } if (!g_is_wait_obj_set(self->wm->pro_layer->self_term_event)) { /* this adds the port to the end of the list, it will already be in the list as -1 the module should use the last one */ if (g_strlen(text) > 0) { list_add_item(self->login_names, (long)g_strdup("port")); list_add_item(self->login_values, (long)g_strdup(text)); } /* always set these */ name = self->wm->session->client_info->hostname; self->mod->mod_set_param(self->mod, "hostname", name); g_snprintf(text, 255, "%d", self->wm->session->client_info->keylayout); self->mod->mod_set_param(self->mod, "keylayout", text); for (i = 0; i < self->login_names->count; i++) { name = (char*)list_get_item(self->login_names, i); value = (char*)list_get_item(self->login_values, i); self->mod->mod_set_param(self->mod, name, value); } /* connect */ if (self->mod->mod_connect(self->mod) == 0) { rv = 0; } } if (rv == 0) { /* sync modifiers */ key_flags = 0; device_flags = 0; if (self->wm->scroll_lock) { key_flags |= 1; } if (self->wm->num_lock) { key_flags |= 2; } if (self->wm->caps_lock) { key_flags |= 4; } if (self->mod != 0) { if (self->mod->mod_event != 0) { self->mod->mod_event(self->mod, 17, key_flags, device_flags, key_flags, device_flags); } } } return rv; } /*****************************************************************************/ /* returns error send a list of channels to the channel handler */ static int APP_CC xrdp_mm_trans_send_channel_setup(struct xrdp_mm* self, struct trans* trans) { int index; int chan_id; int chan_flags; int size; struct stream* s; char chan_name[256]; g_memset(chan_name,0,sizeof(char) * 256); s = trans_get_out_s(trans, 8192); if (s == 0) { return 1; } s_push_layer(s, iso_hdr, 8); s_push_layer(s, mcs_hdr, 8); s_push_layer(s, sec_hdr, 2); index = 0; while (libxrdp_query_channel(self->wm->session, index, chan_name, &chan_flags) == 0) { chan_id = libxrdp_get_channel_id(self->wm->session, chan_name); out_uint8a(s, chan_name, 8); out_uint16_le(s, chan_id); out_uint16_le(s, chan_flags); index++; } s_mark_end(s); s_pop_layer(s, sec_hdr); out_uint16_le(s, index); s_pop_layer(s, mcs_hdr); size = (int)(s->end - s->p); out_uint32_le(s, 3); /* msg id */ out_uint32_le(s, size); /* msg size */ s_pop_layer(s, iso_hdr); size = (int)(s->end - s->p); out_uint32_le(s, 0); /* version */ out_uint32_le(s, size); /* block size */ return trans_force_write(trans); } /*****************************************************************************/ /* returns error */ static int APP_CC xrdp_mm_trans_send_channel_data_response(struct xrdp_mm* self, struct trans* trans) { struct stream* s; s = trans_get_out_s(trans, 8192); if (s == 0) { return 1; } out_uint32_le(s, 0); /* version */ out_uint32_le(s, 8 + 8); /* size */ out_uint32_le(s, 7); /* msg id */ out_uint32_le(s, 8); /* size */ s_mark_end(s); return trans_force_write(trans); } /*****************************************************************************/ /* returns error init is done, sent channel setup */ static int APP_CC xrdp_mm_trans_process_init_response(struct xrdp_mm* self, struct trans* trans) { return xrdp_mm_trans_send_channel_setup(self, trans); } /*****************************************************************************/ /* returns error data coming in from the channel handler, send it to the client */ static int APP_CC xrdp_mm_trans_process_channel_data(struct xrdp_mm* self, struct trans* trans) { struct stream* s; int size; int total_size; int chan_id; int chan_flags; int rv; s = trans_get_in_s(trans); if (s == 0) { return 1; } in_uint16_le(s, chan_id); in_uint16_le(s, chan_flags); in_uint16_le(s, size); in_uint32_le(s, total_size); rv = xrdp_mm_trans_send_channel_data_response(self, trans); if (rv == 0) { rv = libxrdp_send_to_channel(self->wm->session, chan_id, s->p, size, total_size, chan_flags); } return rv; } /*****************************************************************************/ /* returns error process a message for the channel handler */ static int APP_CC xrdp_mm_chan_process_msg(struct xrdp_mm* self, struct trans* trans, struct stream* s) { int rv; int id; int size; char* next_msg; rv = 0; while (s_check_rem(s, 8)) { next_msg = s->p; in_uint32_le(s, id); in_uint32_le(s, size); next_msg += size; switch (id) { case 2: /* channel init response */ rv = xrdp_mm_trans_process_init_response(self, trans); break; case 4: /* channel setup response */ break; case 6: /* channel data response */ break; case 8: /* channel data */ rv = xrdp_mm_trans_process_channel_data(self, trans); break; default: g_writeln("xrdp_mm_chan_process_msg: unknown id %d", id); break; } if (rv != 0) { break; } s->p = next_msg; } return rv; } /*****************************************************************************/ /* this is callback from trans obj returns error */ static int APP_CC xrdp_mm_chan_data_in(struct trans* trans) { struct xrdp_mm* self; struct stream* s; int id; int size; int error; if (trans == 0) { return 1; } self = (struct xrdp_mm*)(trans->callback_data); s = trans_get_in_s(trans); if (s == 0) { return 1; } in_uint32_le(s, id); in_uint32_le(s, size); error = trans_force_read(trans, size - 8); if (error == 0) { /* here, the entire message block is read in, process it */ error = xrdp_mm_chan_process_msg(self, trans, s); } return error; } /*****************************************************************************/ static int APP_CC xrdp_mm_chan_send_init(struct xrdp_mm* self) { struct stream* s; s = trans_get_out_s(self->chan_trans, 8192); if (s == 0) { return 1; } out_uint32_le(s, 0); /* version */ out_uint32_le(s, 8 + 8); /* size */ out_uint32_le(s, 1); /* msg id */ out_uint32_le(s, 8); /* size */ s_mark_end(s); return trans_force_write(self->chan_trans); } /*****************************************************************************/ static int APP_CC xrdp_mm_process_login_response(struct xrdp_mm* self, struct stream* s) { int ok; int display; int rv; int index; int uid; int gid; char text[256]; char ip[256]; char port[256]; g_memset(text,0,sizeof(char) * 256); g_memset(ip,0,sizeof(char) * 256); g_memset(port,0,sizeof(char) * 256); rv = 0; in_uint16_be(s, ok); in_uint16_be(s, display); if (ok) { self->display = display; g_snprintf(text, 255, "xrdp_mm_process_login_response: login successful " "for display %d", display); xrdp_wm_log_msg(self->wm, text); if (xrdp_mm_setup_mod1(self) == 0) { if (xrdp_mm_setup_mod2(self) == 0) { xrdp_mm_get_value(self, "ip", ip, 255); xrdp_wm_set_login_mode(self->wm, 10); self->wm->dragging = 0; /* connect channel redir */ if (strcmp(ip, "127.0.0.1") == 0) { /* unix socket */ self->chan_trans = trans_create(TRANS_MODE_UNIX, 8192, 8192); g_snprintf(port, 255, "/tmp/.xrdp/xrdp_chansrv_socket_%d", 7200 + display); } else { /* tcp */ self->chan_trans = trans_create(TRANS_MODE_TCP, 8192, 8192); g_snprintf(port, 255, "%d", 7200 + display); } self->chan_trans->trans_data_in = xrdp_mm_chan_data_in; self->chan_trans->header_size = 8; self->chan_trans->callback_data = self; /* try to connect up to 4 times */ for (index = 0; index < 4; index++) { if (trans_connect(self->chan_trans, ip, port, 3000) == 0) { self->chan_trans_up = 1; break; } g_sleep(1000); g_writeln("xrdp_mm_process_login_response: connect failed " "trying again..."); } if (!(self->chan_trans_up)) { g_writeln("xrdp_mm_process_login_response: error in trans_connect " "chan"); } if (self->chan_trans_up) { if (xrdp_mm_chan_send_init(self) != 0) { g_writeln("xrdp_mm_process_login_response: error in " "xrdp_mm_chan_send_init"); } } } } } else { xrdp_wm_log_msg(self->wm, "xrdp_mm_process_login_response: " "login failed"); } self->delete_sesman_trans = 1; self->connected_state = 0; if (self->wm->login_mode != 10) { xrdp_wm_set_login_mode(self->wm, 11); xrdp_mm_module_cleanup(self); } return rv; } /*****************************************************************************/ static int xrdp_mm_get_sesman_port(char* port, int port_bytes) { int fd; int error; int index; char* val; char cfg_file[256]; struct list* names; struct list* values; g_memset(cfg_file,0,sizeof(char) * 256); /* default to port 3350 */ g_strncpy(port, "3350", port_bytes - 1); /* see if port is in xrdp.ini file */ g_snprintf(cfg_file, 255, "%s/sesman.ini", XRDP_CFG_PATH); fd = g_file_open(cfg_file); if (fd > 0) { names = list_create(); names->auto_free = 1; values = list_create(); values->auto_free = 1; if (file_read_section(fd, "Globals", names, values) == 0) { for (index = 0; index < names->count; index++) { val = (char*)list_get_item(names, index); if (val != 0) { if (g_strcasecmp(val, "ListenPort") == 0) { val = (char*)list_get_item(values, index); error = g_atoi(val); if ((error > 0) && (error < 65000)) { g_strncpy(port, val, port_bytes - 1); } break; } } } } list_delete(names); list_delete(values); g_file_close(fd); } return 0; } /*****************************************************************************/ /* returns error data coming from client that need to go to channel handler */ int APP_CC xrdp_mm_process_channel_data(struct xrdp_mm* self, tbus param1, tbus param2, tbus param3, tbus param4) { struct stream* s; int rv; int length; int total_length; int flags; int id; char* data; rv = 0; if ((self->chan_trans != 0) && self->chan_trans_up) { s = trans_get_out_s(self->chan_trans, 8192); if (s != 0) { id = LOWORD(param1); flags = HIWORD(param1); length = param2; data = (char*)param3; total_length = param4; if (total_length < length) { g_writeln("WARNING in xrdp_mm_process_channel_data(): total_len < length"); total_length = length; } out_uint32_le(s, 0); /* version */ out_uint32_le(s, 8 + 8 + 2 + 2 + 2 + 4 + length); out_uint32_le(s, 5); /* msg id */ out_uint32_le(s, 8 + 2 + 2 + 2 + 4 + length); out_uint16_le(s, id); out_uint16_le(s, flags); out_uint16_le(s, length); out_uint32_le(s, total_length); out_uint8a(s, data, length); s_mark_end(s); rv = trans_force_write(self->chan_trans); } } return rv; } /*****************************************************************************/ static int APP_CC xrdp_mm_sesman_data_in(struct trans* trans) { struct xrdp_mm* self; struct stream* s; int version; int size; int error; int code; if (trans == 0) { return 1; } self = (struct xrdp_mm*)(trans->callback_data); s = trans_get_in_s(trans); if (s == 0) { return 1; } in_uint32_be(s, version); in_uint32_be(s, size); error = trans_force_read(trans, size - 8); if (error == 0) { in_uint16_be(s, code); switch (code) { case 3: error = xrdp_mm_process_login_response(self, s); break; default: g_writeln("xrdp_mm_sesman_data_in: unknown code %d", code); break; } } return error; } /*****************************************************************************/ int APP_CC xrdp_mm_connect(struct xrdp_mm* self) { struct list* names; struct list* values; int index; int count; int use_sesman; int ok; int rv; char* name; char* value; char ip[256]; char errstr[256]; char text[256]; char port[8]; g_memset(ip,0,sizeof(char) * 256); g_memset(errstr,0,sizeof(char) * 256); g_memset(text,0,sizeof(char) * 256); g_memset(port,0,sizeof(char) * 8); rv = 0; use_sesman = 0; names = self->login_names; values = self->login_values; count = names->count; for (index = 0; index < count; index++) { name = (char*)list_get_item(names, index); value = (char*)list_get_item(values, index); if (g_strcasecmp(name, "ip") == 0) { g_strncpy(ip, value, 255); } else if (g_strcasecmp(name, "port") == 0) { if (g_strcasecmp(value, "-1") == 0) { use_sesman = 1; } } } if (use_sesman) { ok = 0; errstr[0] = 0; trans_delete(self->sesman_trans); self->sesman_trans = trans_create(TRANS_MODE_TCP, 8192, 8192); xrdp_mm_get_sesman_port(port, sizeof(port)); g_snprintf(text, 255, "connecting to sesman ip %s port %s", ip, port); xrdp_wm_log_msg(self->wm, text); self->sesman_trans->trans_data_in = xrdp_mm_sesman_data_in; self->sesman_trans->header_size = 8; self->sesman_trans->callback_data = self; /* try to connect up to 4 times */ for (index = 0; index < 4; index++) { if (trans_connect(self->sesman_trans, ip, port, 3000) == 0) { self->sesman_trans_up = 1; ok = 1; break; } g_sleep(1000); g_writeln("xrdp_mm_connect: connect failed " "trying again..."); } if (ok) { /* fully connect */ xrdp_wm_log_msg(self->wm, "sesman connect ok"); self->connected_state = 1; rv = xrdp_mm_send_login(self); } else { xrdp_wm_log_msg(self->wm, errstr); trans_delete(self->sesman_trans); self->sesman_trans = 0; self->sesman_trans_up = 0; rv = 1; } } else /* no sesman */ { if (xrdp_mm_setup_mod1(self) == 0) { if (xrdp_mm_setup_mod2(self) == 0) { xrdp_wm_set_login_mode(self->wm, 10); } } if (self->wm->login_mode != 10) { xrdp_wm_set_login_mode(self->wm, 11); xrdp_mm_module_cleanup(self); } } self->sesman_controlled = use_sesman; return rv; } /*****************************************************************************/ int APP_CC xrdp_mm_get_wait_objs(struct xrdp_mm* self, tbus* read_objs, int* rcount, tbus* write_objs, int* wcount, int* timeout) { int rv = 0; if (self == 0) { return 0; } rv = 0; if ((self->sesman_trans != 0) && self->sesman_trans_up) { trans_get_wait_objs(self->sesman_trans, read_objs, rcount, timeout); } if ((self->chan_trans != 0) && self->chan_trans_up) { trans_get_wait_objs(self->chan_trans, read_objs, rcount, timeout); } if (self->mod != 0) { if (self->mod->mod_get_wait_objs != 0) { rv = self->mod->mod_get_wait_objs(self->mod, read_objs, rcount, write_objs, wcount, timeout); } } return rv; } /*****************************************************************************/ int APP_CC xrdp_mm_check_wait_objs(struct xrdp_mm* self) { int rv; if (self == 0) { return 0; } rv = 0; if ((self->sesman_trans != 0) && self->sesman_trans_up) { if (trans_check_wait_objs(self->sesman_trans) != 0) { self->delete_sesman_trans = 1; } } if ((self->chan_trans != 0) && self->chan_trans_up) { if (trans_check_wait_objs(self->chan_trans) != 0) { self->delete_chan_trans = 1; } } if (self->mod != 0) { if (self->mod->mod_check_wait_objs != 0) { rv = self->mod->mod_check_wait_objs(self->mod); } } if (self->delete_sesman_trans) { trans_delete(self->sesman_trans); self->sesman_trans = 0; self->sesman_trans_up = 0; self->delete_sesman_trans = 0; } if (self->delete_chan_trans) { trans_delete(self->chan_trans); self->chan_trans = 0; self->chan_trans_up = 0; self->delete_chan_trans = 0; } return rv; } #if 0 /*****************************************************************************/ struct xrdp_painter* APP_CC get_painter(struct xrdp_mod* mod) { struct xrdp_wm* wm; struct xrdp_painter* p; p = (struct xrdp_painter*)(mod->painter); if (p == 0) { wm = (struct xrdp_wm*)(mod->wm); p = xrdp_painter_create(wm, wm->session); mod->painter = (tintptr)p; } return p; } #endif /*****************************************************************************/ int DEFAULT_CC server_begin_update(struct xrdp_mod* mod) { struct xrdp_wm* wm; struct xrdp_painter* p; wm = (struct xrdp_wm*)(mod->wm); p = xrdp_painter_create(wm, wm->session); xrdp_painter_begin_update(p); mod->painter = (long)p; return 0; } /*****************************************************************************/ int DEFAULT_CC server_end_update(struct xrdp_mod* mod) { struct xrdp_painter* p; p = (struct xrdp_painter*)(mod->painter); if (p == 0) { return 0; } xrdp_painter_end_update(p); xrdp_painter_delete(p); mod->painter = 0; return 0; } /*****************************************************************************/ /* got bell signal... try to send to client */ int DEFAULT_CC server_bell_trigger(struct xrdp_mod* mod) { struct xrdp_wm* wm; wm = (struct xrdp_wm*)(mod->wm); xrdp_wm_send_bell(wm); return 0; } /*****************************************************************************/ int DEFAULT_CC server_fill_rect(struct xrdp_mod* mod, int x, int y, int cx, int cy) { struct xrdp_wm* wm; struct xrdp_painter* p; p = (struct xrdp_painter*)(mod->painter); if (p == 0) { return 0; } wm = (struct xrdp_wm*)(mod->wm); xrdp_painter_fill_rect(p, wm->screen, x, y, cx, cy); return 0; } /*****************************************************************************/ int DEFAULT_CC server_screen_blt(struct xrdp_mod* mod, int x, int y, int cx, int cy, int srcx, int srcy) { struct xrdp_wm* wm; struct xrdp_painter* p; p = (struct xrdp_painter*)(mod->painter); if (p == 0) { return 0; } wm = (struct xrdp_wm*)(mod->wm); p->rop = 0xcc; xrdp_painter_copy(p, wm->screen, wm->screen, x, y, cx, cy, srcx, srcy); return 0; } /*****************************************************************************/ int DEFAULT_CC server_paint_rect(struct xrdp_mod* mod, int x, int y, int cx, int cy, char* data, int width, int height, int srcx, int srcy) { struct xrdp_wm* wm; struct xrdp_bitmap* b; struct xrdp_painter* p; p = (struct xrdp_painter*)(mod->painter); if (p == 0) { return 0; } wm = (struct xrdp_wm*)(mod->wm); b = xrdp_bitmap_create_with_data(width, height, wm->screen->bpp, data, wm); xrdp_painter_copy(p, b, wm->screen, x, y, cx, cy, srcx, srcy); xrdp_bitmap_delete(b); return 0; } /*****************************************************************************/ int DEFAULT_CC server_set_pointer(struct xrdp_mod* mod, int x, int y, char* data, char* mask) { struct xrdp_wm* wm; wm = (struct xrdp_wm*)(mod->wm); xrdp_wm_pointer(wm, data, mask, x, y); return 0; } /*****************************************************************************/ int DEFAULT_CC server_palette(struct xrdp_mod* mod, int* palette) { struct xrdp_wm* wm; wm = (struct xrdp_wm*)(mod->wm); if (g_memcmp(wm->palette, palette, 255 * sizeof(int)) != 0) { g_memcpy(wm->palette, palette, 256 * sizeof(int)); xrdp_wm_send_palette(wm); } return 0; } /*****************************************************************************/ int DEFAULT_CC server_msg(struct xrdp_mod* mod, char* msg, int code) { struct xrdp_wm* wm; if (code == 1) { g_writeln(msg); return 0; } wm = (struct xrdp_wm*)(mod->wm); return xrdp_wm_log_msg(wm, msg); } /*****************************************************************************/ int DEFAULT_CC server_is_term(struct xrdp_mod* mod) { return g_is_term(); } /*****************************************************************************/ int DEFAULT_CC server_set_clip(struct xrdp_mod* mod, int x, int y, int cx, int cy) { struct xrdp_painter* p; p = (struct xrdp_painter*)(mod->painter); if (p == 0) { return 0; } return xrdp_painter_set_clip(p, x, y, cx, cy); } /*****************************************************************************/ int DEFAULT_CC server_reset_clip(struct xrdp_mod* mod) { struct xrdp_painter* p; p = (struct xrdp_painter*)(mod->painter); if (p == 0) { return 0; } return xrdp_painter_clr_clip(p); } /*****************************************************************************/ int DEFAULT_CC server_set_fgcolor(struct xrdp_mod* mod, int fgcolor) { struct xrdp_painter* p; p = (struct xrdp_painter*)(mod->painter); if (p == 0) { return 0; } p->fg_color = fgcolor; p->pen.color = p->fg_color; return 0; } /*****************************************************************************/ int DEFAULT_CC server_set_bgcolor(struct xrdp_mod* mod, int bgcolor) { struct xrdp_painter* p; p = (struct xrdp_painter*)(mod->painter); if (p == 0) { return 0; } p->bg_color = bgcolor; return 0; } /*****************************************************************************/ int DEFAULT_CC server_set_opcode(struct xrdp_mod* mod, int opcode) { struct xrdp_painter* p; p = (struct xrdp_painter*)(mod->painter); if (p == 0) { return 0; } p->rop = opcode; return 0; } /*****************************************************************************/ int DEFAULT_CC server_set_mixmode(struct xrdp_mod* mod, int mixmode) { struct xrdp_painter* p; p = (struct xrdp_painter*)(mod->painter); if (p == 0) { return 0; } p->mix_mode = mixmode; return 0; } /*****************************************************************************/ int DEFAULT_CC server_set_brush(struct xrdp_mod* mod, int x_orgin, int y_orgin, int style, char* pattern) { struct xrdp_painter* p; p = (struct xrdp_painter*)(mod->painter); if (p == 0) { return 0; } p->brush.x_orgin = x_orgin; p->brush.y_orgin = y_orgin; p->brush.style = style; g_memcpy(p->brush.pattern, pattern, 8); return 0; } /*****************************************************************************/ int DEFAULT_CC server_set_pen(struct xrdp_mod* mod, int style, int width) { struct xrdp_painter* p; p = (struct xrdp_painter*)(mod->painter); if (p == 0) { return 0; } p->pen.style = style; p->pen.width = width; return 0; } /*****************************************************************************/ int DEFAULT_CC server_draw_line(struct xrdp_mod* mod, int x1, int y1, int x2, int y2) { struct xrdp_wm* wm; struct xrdp_painter* p; p = (struct xrdp_painter*)(mod->painter); if (p == 0) { return 0; } wm = (struct xrdp_wm*)(mod->wm); return xrdp_painter_line(p, wm->screen, x1, y1, x2, y2); } /*****************************************************************************/ int DEFAULT_CC server_add_char(struct xrdp_mod* mod, int font, int charactor, int offset, int baseline, int width, int height, char* data) { struct xrdp_font_char fi; fi.offset = offset; fi.baseline = baseline; fi.width = width; fi.height = height; fi.incby = 0; fi.data = data; return libxrdp_orders_send_font(((struct xrdp_wm*)mod->wm)->session, &fi, font, charactor); } /*****************************************************************************/ int DEFAULT_CC server_draw_text(struct xrdp_mod* mod, int font, int flags, int mixmode, int clip_left, int clip_top, int clip_right, int clip_bottom, int box_left, int box_top, int box_right, int box_bottom, int x, int y, char* data, int data_len) { struct xrdp_wm* wm; struct xrdp_painter* p; p = (struct xrdp_painter*)(mod->painter); if (p == 0) { return 0; } wm = (struct xrdp_wm*)(mod->wm); return xrdp_painter_draw_text2(p, wm->screen, font, flags, mixmode, clip_left, clip_top, clip_right, clip_bottom, box_left, box_top, box_right, box_bottom, x, y, data, data_len); } /*****************************************************************************/ int DEFAULT_CC server_reset(struct xrdp_mod* mod, int width, int height, int bpp) { struct xrdp_wm* wm; wm = (struct xrdp_wm*)(mod->wm); if (wm->client_info == 0) { return 1; } /* older client can't resize */ if (wm->client_info->build <= 419) { return 0; } /* if same, don't need to do anything */ if (wm->client_info->width == width && wm->client_info->height == height && wm->client_info->bpp == bpp) { return 0; } /* reset lib, client_info gets updated in libxrdp_reset */ if (libxrdp_reset(wm->session, width, height, bpp) != 0) { return 1; } /* reset cache */ xrdp_cache_reset(wm->cache, wm->client_info); /* resize the main window */ xrdp_bitmap_resize(wm->screen, wm->client_info->width, wm->client_info->height); /* load some stuff */ xrdp_wm_load_static_colors(wm); xrdp_wm_load_static_pointers(wm); return 0; } /*****************************************************************************/ int DEFAULT_CC server_query_channel(struct xrdp_mod* mod, int index, char* channel_name, int* channel_flags) { struct xrdp_wm* wm; wm = (struct xrdp_wm*)(mod->wm); if (wm->mm->sesman_controlled) { return 1; } return libxrdp_query_channel(wm->session, index, channel_name, channel_flags); } /*****************************************************************************/ /* returns -1 on error */ int DEFAULT_CC server_get_channel_id(struct xrdp_mod* mod, char* name) { struct xrdp_wm* wm; wm = (struct xrdp_wm*)(mod->wm); if (wm->mm->sesman_controlled) { return -1; } return libxrdp_get_channel_id(wm->session, name); } /*****************************************************************************/ int DEFAULT_CC server_send_to_channel(struct xrdp_mod* mod, int channel_id, char* data, int data_len, int total_data_len, int flags) { struct xrdp_wm* wm; wm = (struct xrdp_wm*)(mod->wm); if (wm->mm->sesman_controlled) { return 1; } return libxrdp_send_to_channel(wm->session, channel_id, data, data_len, total_data_len, flags); } xrdp-0.6.0/xrdp/xrdp_painter.c000066400000000000000000000417471203155130500163220ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2004-2010 painter, gc */ #include "xrdp.h" /*****************************************************************************/ struct xrdp_painter* APP_CC xrdp_painter_create(struct xrdp_wm* wm, struct xrdp_session* session) { struct xrdp_painter* self; self = (struct xrdp_painter*)g_malloc(sizeof(struct xrdp_painter), 1); self->wm = wm; self->session = session; self->rop = 0xcc; /* copy gota use 0xcc*/ self->clip_children = 1; return self; } /*****************************************************************************/ void APP_CC xrdp_painter_delete(struct xrdp_painter* self) { if (self == 0) { return; } g_free(self); } /*****************************************************************************/ int APP_CC xrdp_painter_begin_update(struct xrdp_painter* self) { if (self == 0) { return 0; } libxrdp_orders_init(self->session); return 0; } /*****************************************************************************/ int APP_CC xrdp_painter_end_update(struct xrdp_painter* self) { if (self == 0) { return 0; } libxrdp_orders_send(self->session); return 0; } /*****************************************************************************/ int APP_CC xrdp_painter_font_needed(struct xrdp_painter* self) { if (self->font == 0) { self->font = self->wm->default_font; } return 0; } /*****************************************************************************/ /* returns boolean, true if there is something to draw */ static int APP_CC xrdp_painter_clip_adj(struct xrdp_painter* self, int* x, int* y, int* cx, int* cy) { int dx; int dy; if (!self->use_clip) { return 1; } if (self->clip.left > *x) { dx = self->clip.left - *x; } else { dx = 0; } if (self->clip.top > *y) { dy = self->clip.top - *y; } else { dy = 0; } if (*x + *cx > self->clip.right) { *cx = *cx - ((*x + *cx) - self->clip.right); } if (*y + *cy > self->clip.bottom) { *cy = *cy - ((*y + *cy) - self->clip.bottom); } *cx = *cx - dx; *cy = *cy - dy; if (*cx <= 0) { return 0; } if (*cy <= 0) { return 0; } *x = *x + dx; *y = *y + dy; return 1; } /*****************************************************************************/ int APP_CC xrdp_painter_set_clip(struct xrdp_painter* self, int x, int y, int cx, int cy) { self->use_clip = &self->clip; self->clip.left = x; self->clip.top = y; self->clip.right = x + cx; self->clip.bottom = y + cy; return 0; } /*****************************************************************************/ int APP_CC xrdp_painter_clr_clip(struct xrdp_painter* self) { self->use_clip = 0; return 0; } /*****************************************************************************/ static int APP_CC xrdp_painter_rop(int rop, int src, int dst) { switch (rop & 0x0f) { case 0x0: return 0; case 0x1: return ~(src | dst); case 0x2: return (~src) & dst; case 0x3: return ~src; case 0x4: return src & (~dst); case 0x5: return ~(dst); case 0x6: return src ^ dst; case 0x7: return ~(src & dst); case 0x8: return src & dst; case 0x9: return ~(src) ^ dst; case 0xa: return dst; case 0xb: return (~src) | dst; case 0xc: return src; case 0xd: return src | (~dst); case 0xe: return src | dst; case 0xf: return ~0; } return dst; } /*****************************************************************************/ int APP_CC xrdp_painter_text_width(struct xrdp_painter* self, char* text) { int index; int rv; int len; struct xrdp_font_char* font_item; twchar* wstr; xrdp_painter_font_needed(self); if (self->font == 0) { return 0; } if (text == 0) { return 0; } rv = 0; len = g_mbstowcs(0, text, 0); wstr = (twchar*)g_malloc((len + 2) * sizeof(twchar), 0); g_mbstowcs(wstr, text, len + 1); for (index = 0; index < len; index++) { font_item = self->font->font_items + wstr[index]; rv = rv + font_item->incby; } g_free(wstr); return rv; } /*****************************************************************************/ int APP_CC xrdp_painter_text_height(struct xrdp_painter* self, char* text) { int index; int rv; int len; struct xrdp_font_char* font_item; twchar* wstr; xrdp_painter_font_needed(self); if (self->font == 0) { return 0; } if (text == 0) { return 0; } rv = 0; len = g_mbstowcs(0, text, 0); wstr = (twchar*)g_malloc((len + 2) * sizeof(twchar), 0); g_mbstowcs(wstr, text, len + 1); for (index = 0; index < len; index++) { font_item = self->font->font_items + wstr[index]; rv = MAX(rv, font_item->height); } g_free(wstr); return rv; } /*****************************************************************************/ static int APP_CC xrdp_painter_setup_brush(struct xrdp_painter* self, struct xrdp_brush* out_brush, struct xrdp_brush* in_brush) { int cache_id; g_memcpy(out_brush, in_brush, sizeof(struct xrdp_brush)); if (in_brush->style == 3) { if (self->session->client_info->brush_cache_code == 1) { cache_id = xrdp_cache_add_brush(self->wm->cache, in_brush->pattern); g_memset(out_brush->pattern, 0, 8); out_brush->pattern[0] = cache_id; out_brush->style = 0x81; } } return 0; } /*****************************************************************************/ /* fill in an area of the screen with one color */ int APP_CC xrdp_painter_fill_rect(struct xrdp_painter* self, struct xrdp_bitmap* bitmap, int x, int y, int cx, int cy) { struct xrdp_rect clip_rect; struct xrdp_rect draw_rect; struct xrdp_rect rect; struct xrdp_region* region; struct xrdp_brush brush; int k; int dx; int dy; int rop; if (self == 0) { return 0; } /* todo data */ if (bitmap->type == WND_TYPE_BITMAP) /* 0 */ { return 0; } xrdp_bitmap_get_screen_clip(bitmap, self, &clip_rect, &dx, &dy); region = xrdp_region_create(self->wm); xrdp_wm_get_vis_region(self->wm, bitmap, x, y, cx, cy, region, self->clip_children); x += dx; y += dy; if (self->mix_mode == 0 && self->rop == 0xcc) { k = 0; while (xrdp_region_get_rect(region, k, &rect) == 0) { if (rect_intersect(&rect, &clip_rect, &draw_rect)) { libxrdp_orders_rect(self->session, x, y, cx, cy, self->fg_color, &draw_rect); } k++; } } else if (self->mix_mode == 0 && ((self->rop & 0xf) == 0x0 || /* black */ (self->rop & 0xf) == 0xf || /* white */ (self->rop & 0xf) == 0x5)) /* DSTINVERT */ { k = 0; while (xrdp_region_get_rect(region, k, &rect) == 0) { if (rect_intersect(&rect, &clip_rect, &draw_rect)) { libxrdp_orders_dest_blt(self->session, x, y, cx, cy, self->rop, &draw_rect); } k++; } } else { k = 0; rop = self->rop; /* if opcode is in the form 0x00, 0x11, 0x22, ... convert it */ if (((rop & 0xf0) >> 4) == (rop & 0xf)) { switch (rop) { case 0x66: /* xor */ rop = 0x5a; break; case 0xaa: /* noop */ rop = 0xfb; break; case 0xcc: /* copy */ rop = 0xf0; break; case 0x88: /* and */ rop = 0xc0; break; } } xrdp_painter_setup_brush(self, &brush, &self->brush); while (xrdp_region_get_rect(region, k, &rect) == 0) { if (rect_intersect(&rect, &clip_rect, &draw_rect)) { libxrdp_orders_pat_blt(self->session, x, y, cx, cy, rop, self->bg_color, self->fg_color, &brush, &draw_rect); } k++; } } xrdp_region_delete(region); return 0; } /*****************************************************************************/ int APP_CC xrdp_painter_draw_text(struct xrdp_painter* self, struct xrdp_bitmap* bitmap, int x, int y, const char* text) { int i; int f; int c; int k; int x1; int y1; int flags; int len; int index; int total_width; int total_height; int dx; int dy; char* data; struct xrdp_region* region; struct xrdp_rect rect; struct xrdp_rect clip_rect; struct xrdp_rect draw_rect; struct xrdp_font* font; struct xrdp_font_char* font_item; twchar* wstr; if (self == 0) { return 0; } len = g_mbstowcs(0, text, 0); if (len < 1) { return 0; } /* todo data */ if (bitmap->type == 0) { return 0; } xrdp_painter_font_needed(self); if (self->font == 0) { return 0; } /* convert to wide char */ wstr = (twchar*)g_malloc((len + 2) * sizeof(twchar), 0); g_mbstowcs(wstr, text, len + 1); font = self->font; f = 0; k = 0; total_width = 0; total_height = 0; data = (char*)g_malloc(len * 4, 1); for (index = 0; index < len; index++) { font_item = font->font_items + wstr[index]; i = xrdp_cache_add_char(self->wm->cache, font_item); f = HIWORD(i); c = LOWORD(i); data[index * 2] = c; data[index * 2 + 1] = k; k = font_item->incby; total_width += k; total_height = MAX(total_height, font_item->height); } xrdp_bitmap_get_screen_clip(bitmap, self, &clip_rect, &dx, &dy); region = xrdp_region_create(self->wm); xrdp_wm_get_vis_region(self->wm, bitmap, x, y, total_width, total_height, region, self->clip_children); x += dx; y += dy; k = 0; while (xrdp_region_get_rect(region, k, &rect) == 0) { if (rect_intersect(&rect, &clip_rect, &draw_rect)) { x1 = x; y1 = y + total_height; flags = 0x03; /* 0x03 0x73; TEXT2_IMPLICIT_X and something else */ libxrdp_orders_text(self->session, f, flags, 0, self->fg_color, 0, x - 1, y - 1, x + total_width, y + total_height, 0, 0, 0, 0, x1, y1, data, len * 2, &draw_rect); } k++; } xrdp_region_delete(region); g_free(data); g_free(wstr); return 0; } /*****************************************************************************/ int APP_CC xrdp_painter_draw_text2(struct xrdp_painter* self, struct xrdp_bitmap* bitmap, int font, int flags, int mixmode, int clip_left, int clip_top, int clip_right, int clip_bottom, int box_left, int box_top, int box_right, int box_bottom, int x, int y, char* data, int data_len) { struct xrdp_rect clip_rect; struct xrdp_rect draw_rect; struct xrdp_rect rect; struct xrdp_region* region; int k; int dx; int dy; if (self == 0) { return 0; } /* todo data */ if (bitmap->type == WND_TYPE_BITMAP) { return 0; } xrdp_bitmap_get_screen_clip(bitmap, self, &clip_rect, &dx, &dy); region = xrdp_region_create(self->wm); if (box_right - box_left > 1) { xrdp_wm_get_vis_region(self->wm, bitmap, box_left, box_top, box_right - box_left, box_bottom - box_top, region, self->clip_children); } else { xrdp_wm_get_vis_region(self->wm, bitmap, clip_left, clip_top, clip_right - clip_left, clip_bottom - clip_top, region, self->clip_children); } clip_left += dx; clip_top += dy; clip_right += dx; clip_bottom += dy; box_left += dx; box_top += dy; box_right += dx; box_bottom += dy; x += dx; y += dy; k = 0; while (xrdp_region_get_rect(region, k, &rect) == 0) { if (rect_intersect(&rect, &clip_rect, &draw_rect)) { libxrdp_orders_text(self->session, font, flags, mixmode, self->fg_color, self->bg_color, clip_left, clip_top, clip_right, clip_bottom, box_left, box_top, box_right, box_bottom, x, y, data, data_len, &draw_rect); } k++; } xrdp_region_delete(region); return 0; } /*****************************************************************************/ int APP_CC xrdp_painter_copy(struct xrdp_painter* self, struct xrdp_bitmap* src, struct xrdp_bitmap* dst, int x, int y, int cx, int cy, int srcx, int srcy) { struct xrdp_rect clip_rect; struct xrdp_rect draw_rect; struct xrdp_rect rect1; struct xrdp_rect rect2; struct xrdp_region* region; struct xrdp_bitmap* b; int i; int j; int k; int dx; int dy; int palette_id; int bitmap_id; int cache_id; int cache_idx; int dstx; int dsty; int w; int h; if (self == 0 || src == 0 || dst == 0) { return 0; } /* todo data */ if (dst->type == WND_TYPE_BITMAP) { return 0; } if (src == dst && src->wm->screen == src) { xrdp_bitmap_get_screen_clip(dst, self, &clip_rect, &dx, &dy); region = xrdp_region_create(self->wm); xrdp_wm_get_vis_region(self->wm, dst, x, y, cx, cy, region, self->clip_children); x += dx; y += dy; srcx += dx; srcy += dy; k = 0; while (xrdp_region_get_rect(region, k, &rect1) == 0) { if (rect_intersect(&rect1, &clip_rect, &draw_rect)) { libxrdp_orders_screen_blt(self->session, x, y, cx, cy, srcx, srcy, self->rop, &draw_rect); } k++; } xrdp_region_delete(region); } else if (src->data != 0) /* todo, the non bitmap cache part is gone, it should be put back */ { xrdp_bitmap_get_screen_clip(dst, self, &clip_rect, &dx, &dy); region = xrdp_region_create(self->wm); xrdp_wm_get_vis_region(self->wm, dst, x, y, cx, cy, region, self->clip_children); x += dx; y += dy; palette_id = 0; j = srcy; while (j < src->height) { i = srcx; while (i < src->width) { w = MIN(64, src->width - i); h = MIN(64, src->height - j); b = xrdp_bitmap_create(w, h, self->wm->screen->bpp, 0, self->wm); xrdp_bitmap_copy_box_with_crc(src, b, i, j, w, h); bitmap_id = xrdp_cache_add_bitmap(self->wm->cache, b); cache_id = HIWORD(bitmap_id); cache_idx = LOWORD(bitmap_id); dstx = (x + i) - srcx; dsty = (y + j) - srcy; k = 0; while (xrdp_region_get_rect(region, k, &rect1) == 0) { if (rect_intersect(&rect1, &clip_rect, &rect2)) { MAKERECT(rect1, dstx, dsty, w, h); if (rect_intersect(&rect2, &rect1, &draw_rect)) { libxrdp_orders_mem_blt(self->session, cache_id, palette_id, dstx, dsty, w, h, self->rop, 0, 0, cache_idx, &draw_rect); } } k++; } i += 64; } j += 64; } xrdp_region_delete(region); } return 0; } /*****************************************************************************/ int APP_CC xrdp_painter_line(struct xrdp_painter* self, struct xrdp_bitmap* bitmap, int x1, int y1, int x2, int y2) { struct xrdp_rect clip_rect; struct xrdp_rect draw_rect; struct xrdp_rect rect; struct xrdp_region* region; int k; int dx; int dy; int rop; if (self == 0) { return 0; } /* todo data */ if (bitmap->type == WND_TYPE_BITMAP) { return 0; } xrdp_bitmap_get_screen_clip(bitmap, self, &clip_rect, &dx, &dy); region = xrdp_region_create(self->wm); xrdp_wm_get_vis_region(self->wm, bitmap, MIN(x1, x2), MIN(y1, y2), g_abs(x1 - x2) + 1, g_abs(y1 - y2) + 1, region, self->clip_children); x1 += dx; y1 += dy; x2 += dx; y2 += dy; k = 0; rop = self->rop; if (rop < 0x01 || rop > 0x10) { rop = (rop & 0xf) + 1; } while (xrdp_region_get_rect(region, k, &rect) == 0) { if (rect_intersect(&rect, &clip_rect, &draw_rect)) { libxrdp_orders_line(self->session, 1, x1, y1, x2, y2, rop, self->bg_color, &self->pen, &draw_rect); } k++; } xrdp_region_delete(region); return 0; } xrdp-0.6.0/xrdp/xrdp_process.c000066400000000000000000000123601203155130500163230ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2004-2010 main rdp process */ #include "xrdp.h" static int g_session_id = 0; /*****************************************************************************/ /* always called from xrdp_listen thread */ struct xrdp_process* APP_CC xrdp_process_create(struct xrdp_listen* owner, tbus done_event) { struct xrdp_process* self; char event_name[256]; int pid; self = (struct xrdp_process*)g_malloc(sizeof(struct xrdp_process), 1); self->lis_layer = owner; self->done_event = done_event; g_session_id++; self->session_id = g_session_id; pid = g_getpid(); g_snprintf(event_name, 255, "xrdp_%8.8x_process_self_term_event_%8.8x", pid, self->session_id); self->self_term_event = g_create_wait_obj(event_name); return self; } /*****************************************************************************/ void APP_CC xrdp_process_delete(struct xrdp_process* self) { if (self == 0) { return; } g_delete_wait_obj(self->self_term_event); libxrdp_exit(self->session); xrdp_wm_delete(self->wm); trans_delete(self->server_trans); g_free(self); } /*****************************************************************************/ static int APP_CC xrdp_process_loop(struct xrdp_process* self) { int rv; rv = 0; if (self->session != 0) { rv = libxrdp_process_data(self->session); } if ((self->wm == 0) && (self->session->up_and_running) && (rv == 0)) { DEBUG(("calling xrdp_wm_init and creating wm")); self->wm = xrdp_wm_create(self, self->session->client_info); /* at this point the wm(window manager) is create and wm::login_mode is zero and login_mode_event is set so xrdp_wm_init should be called by xrdp_wm_check_wait_objs */ } return rv; } /*****************************************************************************/ /* returns boolean */ /* this is so libxrdp.so can known when to quit looping */ static int DEFAULT_CC xrdp_is_term(void) { return g_is_term(); } /*****************************************************************************/ static int APP_CC xrdp_process_mod_end(struct xrdp_process* self) { if (self->wm != 0) { if (self->wm->mm != 0) { if (self->wm->mm->mod != 0) { if (self->wm->mm->mod->mod_end != 0) { return self->wm->mm->mod->mod_end(self->wm->mm->mod); } } } } return 0; } /*****************************************************************************/ static int DEFAULT_CC xrdp_process_data_in(struct trans* self) { struct xrdp_process* pro; DEBUG(("xrdp_process_data_in")); pro = (struct xrdp_process*)(self->callback_data); if (xrdp_process_loop(pro) != 0) { return 1; } return 0; } /*****************************************************************************/ int APP_CC xrdp_process_main_loop(struct xrdp_process* self) { int robjs_count; int wobjs_count; int cont; int timeout = 0; tbus robjs[32]; tbus wobjs[32]; tbus term_obj; DEBUG(("xrdp_process_main_loop")); self->status = 1; self->server_trans->trans_data_in = xrdp_process_data_in; self->server_trans->callback_data = self; self->session = libxrdp_init((tbus)self, self->server_trans); /* this callback function is in xrdp_wm.c */ self->session->callback = callback; /* this function is just above */ self->session->is_term = xrdp_is_term; if (libxrdp_process_incomming(self->session) == 0) { term_obj = g_get_term_event(); cont = 1; while (cont) { /* build the wait obj list */ timeout = -1; robjs_count = 0; wobjs_count = 0; robjs[robjs_count++] = term_obj; robjs[robjs_count++] = self->self_term_event; xrdp_wm_get_wait_objs(self->wm, robjs, &robjs_count, wobjs, &wobjs_count, &timeout); trans_get_wait_objs(self->server_trans, robjs, &robjs_count, &timeout); /* wait */ if (g_obj_wait(robjs, robjs_count, wobjs, wobjs_count, timeout) != 0) { /* error, should not get here */ g_sleep(100); } if (g_is_wait_obj_set(term_obj)) /* term */ { break; } if (g_is_wait_obj_set(self->self_term_event)) { break; } if (xrdp_wm_check_wait_objs(self->wm) != 0) { break; } if (trans_check_wait_objs(self->server_trans) != 0) { break; } } libxrdp_disconnect(self->session); } xrdp_process_mod_end(self); libxrdp_exit(self->session); self->session = 0; self->status = -1; g_set_wait_obj(self->done_event); return 0; } xrdp-0.6.0/xrdp/xrdp_region.c000066400000000000000000000244321203155130500161330ustar00rootroot00000000000000 /* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2004-2010 region */ #include "xrdp.h" /*****************************************************************************/ struct xrdp_region* APP_CC xrdp_region_create(struct xrdp_wm* wm) { struct xrdp_region* self; self = (struct xrdp_region*)g_malloc(sizeof(struct xrdp_region), 1); self->wm = wm; self->rects = list_create(); self->rects->auto_free = 1; return self; } /*****************************************************************************/ void APP_CC xrdp_region_delete(struct xrdp_region* self) { if (self == 0) { return; } list_delete(self->rects); g_free(self); } /*****************************************************************************/ int APP_CC xrdp_region_add_rect(struct xrdp_region* self, struct xrdp_rect* rect) { struct xrdp_rect* r; r = (struct xrdp_rect*)g_malloc(sizeof(struct xrdp_rect), 1); *r = *rect; list_add_item(self->rects, (long)r); return 0; } /*****************************************************************************/ int APP_CC xrdp_region_insert_rect(struct xrdp_region* self, int i, int left, int top, int right, int bottom) { struct xrdp_rect* r; r = (struct xrdp_rect*)g_malloc(sizeof(struct xrdp_rect), 1); r->left = left; r->top = top; r->right = right; r->bottom = bottom; list_insert_item(self->rects, i, (long)r); return 0; } /*****************************************************************************/ int APP_CC xrdp_region_subtract_rect(struct xrdp_region* self, struct xrdp_rect* rect) { struct xrdp_rect* r; struct xrdp_rect rect1; int i; for (i = self->rects->count - 1; i >= 0; i--) { r = (struct xrdp_rect*)list_get_item(self->rects, i); rect1 = *r; r = &rect1; if (rect->left <= r->left && rect->top <= r->top && rect->right >= r->right && rect->bottom >= r->bottom) { /* rect is not visible */ list_remove_item(self->rects, i); } else if (rect->right < r->left || rect->bottom < r->top || rect->top > r->bottom || rect->left > r->right) { /* rect are not related */ } else if (rect->left <= r->left && rect->right >= r->right && rect->bottom < r->bottom && rect->top <= r->top) { /* partially covered(whole top) */ list_remove_item(self->rects, i); xrdp_region_insert_rect(self, i, r->left, rect->bottom, r->right, r->bottom); } else if (rect->top <= r->top && rect->bottom >= r->bottom && rect->right < r->right && rect->left <= r->left) { /* partially covered(left) */ list_remove_item(self->rects, i); xrdp_region_insert_rect(self, i, rect->right, r->top, r->right, r->bottom); } else if (rect->left <= r->left && rect->right >= r->right && rect->top > r->top && rect->bottom >= r->bottom) { /* partially covered(bottom) */ list_remove_item(self->rects, i); xrdp_region_insert_rect(self, i, r->left, r->top, r->right, rect->top); } else if (rect->top <= r->top && rect->bottom >= r->bottom && rect->left > r->left && rect->right >= r->right) { /* partially covered(right) */ list_remove_item(self->rects, i); xrdp_region_insert_rect(self, i, r->left, r->top, rect->left, r->bottom); } else if (rect->left <= r->left && rect->top <= r->top && rect->right < r->right && rect->bottom < r->bottom) { /* partially covered(top left) */ list_remove_item(self->rects, i); xrdp_region_insert_rect(self, i, rect->right, r->top, r->right, rect->bottom); xrdp_region_insert_rect(self, i, r->left, rect->bottom, r->right, r->bottom); } else if (rect->left <= r->left && rect->bottom >= r->bottom && rect->right < r->right && rect->top > r->top) { /* partially covered(bottom left) */ list_remove_item(self->rects, i); xrdp_region_insert_rect(self, i, r->left, r->top, r->right, rect->top); xrdp_region_insert_rect(self, i, rect->right, rect->top, r->right, r->bottom); } else if (rect->left > r->left && rect->right >= r->right && rect->top <= r->top && rect->bottom < r->bottom) { /* partially covered(top right) */ list_remove_item(self->rects, i); xrdp_region_insert_rect(self, i, r->left, r->top, rect->left, r->bottom); xrdp_region_insert_rect(self, i, rect->left, rect->bottom, r->right, r->bottom); } else if (rect->left > r->left && rect->right >= r->right && rect->top > r->top && rect->bottom >= r->bottom) { /* partially covered(bottom right) */ list_remove_item(self->rects, i); xrdp_region_insert_rect(self, i, r->left, r->top, r->right, rect->top); xrdp_region_insert_rect(self, i, r->left, rect->top, rect->left, r->bottom); } else if (rect->left > r->left && rect->top <= r->top && rect->right < r->right && rect->bottom >= r->bottom) { /* 2 rects, one on each end */ list_remove_item(self->rects, i); xrdp_region_insert_rect(self, i, r->left, r->top, rect->left, r->bottom); xrdp_region_insert_rect(self, i, rect->right, r->top, r->right, r->bottom); } else if (rect->left <= r->left && rect->top > r->top && rect->right >= r->right && rect->bottom < r->bottom) { /* 2 rects, one on each end */ list_remove_item(self->rects, i); xrdp_region_insert_rect(self, i, r->left, r->top, r->right, rect->top); xrdp_region_insert_rect(self, i, r->left, rect->bottom, r->right, r->bottom); } else if (rect->left > r->left && rect->right < r->right && rect->top <= r->top && rect->bottom < r->bottom) { /* partially covered(top) */ list_remove_item(self->rects, i); xrdp_region_insert_rect(self, i, r->left, r->top, rect->left, r->bottom); xrdp_region_insert_rect(self, i, rect->left, rect->bottom, rect->right, r->bottom); xrdp_region_insert_rect(self, i, rect->right, r->top, r->right, r->bottom); } else if (rect->top > r->top && rect->bottom < r->bottom && rect->left <= r->left && rect->right < r->right) { /* partially covered(left) */ list_remove_item(self->rects, i); xrdp_region_insert_rect(self, i, r->left, r->top, r->right, rect->top); xrdp_region_insert_rect(self, i, rect->right, rect->top, r->right, rect->bottom); xrdp_region_insert_rect(self, i, r->left, rect->bottom, r->right, r->bottom); } else if (rect->left > r->left && rect->right < r->right && rect->bottom >= r->bottom && rect->top > r->top) { /* partially covered(bottom) */ list_remove_item(self->rects, i); xrdp_region_insert_rect(self, i, r->left, r->top, rect->left, r->bottom); xrdp_region_insert_rect(self, i, rect->left, r->top, rect->right, rect->top); xrdp_region_insert_rect(self, i, rect->right, r->top, r->right, r->bottom); } else if (rect->top > r->top && rect->bottom < r->bottom && rect->right >= r->right && rect->left > r->left) { /* partially covered(right) */ list_remove_item(self->rects, i); xrdp_region_insert_rect(self, i, r->left, r->top, r->right, rect->top); xrdp_region_insert_rect(self, i, r->left, rect->top, rect->left, rect->bottom); xrdp_region_insert_rect(self, i, r->left, rect->bottom, r->right, r->bottom); } else if (rect->left > r->left && rect->top > r->top && rect->right < r->right && rect->bottom < r->bottom) { /* totally contained, 4 rects */ list_remove_item(self->rects, i); xrdp_region_insert_rect(self, i, r->left, r->top, r->right, rect->top); xrdp_region_insert_rect(self, i, r->left, rect->top, rect->left, rect->bottom); xrdp_region_insert_rect(self, i, r->left, rect->bottom, r->right, r->bottom); xrdp_region_insert_rect(self, i, rect->right, rect->top, r->right, rect->bottom); } else { g_writeln("error in xrdp_region_subtract_rect"); } } return 0; } /*****************************************************************************/ int APP_CC xrdp_region_get_rect(struct xrdp_region* self, int index, struct xrdp_rect* rect) { struct xrdp_rect* r; r = (struct xrdp_rect*)list_get_item(self->rects, index); if (r == 0) { return 1; } *rect = *r; return 0; } xrdp-0.6.0/xrdp/xrdp_types.h000066400000000000000000000266641203155130500160320ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2004-2010 types */ /* lib */ struct xrdp_mod { int size; /* size of this struct */ int version; /* internal version */ /* client functions */ int (*mod_start)(struct xrdp_mod* v, int w, int h, int bpp); int (*mod_connect)(struct xrdp_mod* v); int (*mod_event)(struct xrdp_mod* v, int msg, long param1, long param2, long param3, long param4); int (*mod_signal)(struct xrdp_mod* v); int (*mod_end)(struct xrdp_mod* v); int (*mod_set_param)(struct xrdp_mod* v, char* name, char* value); int (*mod_session_change)(struct xrdp_mod* v, int, int); int (*mod_get_wait_objs)(struct xrdp_mod* v, tbus* read_objs, int* rcount, tbus* write_objs, int* wcount, int* timeout); int (*mod_check_wait_objs)(struct xrdp_mod* v); long mod_dumby[100 - 9]; /* align, 100 minus the number of mod functions above */ /* server functions */ int (*server_begin_update)(struct xrdp_mod* v); int (*server_end_update)(struct xrdp_mod* v); int (*server_fill_rect)(struct xrdp_mod* v, int x, int y, int cx, int cy); int (*server_screen_blt)(struct xrdp_mod* v, int x, int y, int cx, int cy, int srcx, int srcy); int (*server_paint_rect)(struct xrdp_mod* v, int x, int y, int cx, int cy, char* data, int width, int height, int srcx, int srcy); int (*server_set_pointer)(struct xrdp_mod* v, int x, int y, char* data, char* mask); int (*server_palette)(struct xrdp_mod* v, int* palette); int (*server_msg)(struct xrdp_mod* v, char* msg, int code); int (*server_is_term)(struct xrdp_mod* v); int (*server_set_clip)(struct xrdp_mod* v, int x, int y, int cx, int cy); int (*server_reset_clip)(struct xrdp_mod* v); int (*server_set_fgcolor)(struct xrdp_mod* v, int fgcolor); int (*server_set_bgcolor)(struct xrdp_mod* v, int bgcolor); int (*server_set_opcode)(struct xrdp_mod* v, int opcode); int (*server_set_mixmode)(struct xrdp_mod* v, int mixmode); int (*server_set_brush)(struct xrdp_mod* v, int x_orgin, int y_orgin, int style, char* pattern); int (*server_set_pen)(struct xrdp_mod* v, int style, int width); int (*server_draw_line)(struct xrdp_mod* v, int x1, int y1, int x2, int y2); int (*server_add_char)(struct xrdp_mod* v, int font, int charactor, int offset, int baseline, int width, int height, char* data); int (*server_draw_text)(struct xrdp_mod* v, int font, int flags, int mixmode, int clip_left, int clip_top, int clip_right, int clip_bottom, int box_left, int box_top, int box_right, int box_bottom, int x, int y, char* data, int data_len); int (*server_reset)(struct xrdp_mod* v, int width, int height, int bpp); int (*server_query_channel)(struct xrdp_mod* v, int index, char* channel_name, int* channel_flags); int (*server_get_channel_id)(struct xrdp_mod* v, char* name); int (*server_send_to_channel)(struct xrdp_mod* v, int channel_id, char* data, int data_len, int total_data_len, int flags); int (*server_bell_trigger)(struct xrdp_mod* v); long server_dumby[100 - 25]; /* align, 100 minus the number of server functions above */ /* common */ long handle; /* pointer to self as int */ long wm; /* struct xrdp_wm* */ long painter; int sck; }; /* header for bmp file */ struct xrdp_bmp_header { int size; int image_width; int image_height; short planes; short bit_count; int compression; int image_size; int x_pels_per_meter; int y_pels_per_meter; int clr_used; int clr_important; }; struct xrdp_palette_item { int stamp; int palette[256]; }; struct xrdp_bitmap_item { int stamp; struct xrdp_bitmap* bitmap; }; struct xrdp_char_item { int stamp; struct xrdp_font_char font_item; }; struct xrdp_pointer_item { int stamp; int x; /* hotspot */ int y; char data[32 * 32 * 3]; char mask[32 * 32 / 8]; }; struct xrdp_brush_item { int stamp; /* expand this to a structure to handle more complicated brushes for now its 8x8 1bpp brushes only */ char pattern[8]; }; /* differnce caches */ struct xrdp_cache { struct xrdp_wm* wm; /* owner */ struct xrdp_session* session; /* palette */ int palette_stamp; struct xrdp_palette_item palette_items[6]; /* bitmap */ int bitmap_stamp; struct xrdp_bitmap_item bitmap_items[3][2000]; int use_bitmap_comp; int cache1_entries; int cache1_size; int cache2_entries; int cache2_size; int cache3_entries; int cache3_size; int bitmap_cache_persist_enable; int bitmap_cache_version; /* font */ int char_stamp; struct xrdp_char_item char_items[12][256]; /* pointer */ int pointer_stamp; struct xrdp_pointer_item pointer_items[32]; int pointer_cache_entries; int brush_stamp; struct xrdp_brush_item brush_items[64]; }; struct xrdp_mm { struct xrdp_wm* wm; /* owner */ int connected_state; /* true if connected to sesman else false */ struct trans* sesman_trans; /* connection to sesman */ int sesman_trans_up; /* true once connected to sesman */ int delete_sesman_trans; /* boolean set when done with sesman connection */ struct list* login_names; struct list* login_values; /* mod vars */ long mod_handle; /* returned from g_load_library */ struct xrdp_mod* (*mod_init)(void); int (*mod_exit)(struct xrdp_mod*); struct xrdp_mod* mod; /* module interface */ int display; /* 10 for :10.0, 11 for :11.0, etc */ int code; /* 0 Xvnc session 10 X11rdp session */ int sesman_controlled; /* true if this is a sesman session */ struct trans* chan_trans; /* connection to chansrv */ int chan_trans_up; /* true once connected to chansrv */ int delete_chan_trans; /* boolean set when done with channel connection */ }; struct xrdp_key_info { int sym; int chr; }; struct xrdp_keymap { struct xrdp_key_info keys_noshift[256]; struct xrdp_key_info keys_shift[256]; struct xrdp_key_info keys_altgr[256]; struct xrdp_key_info keys_capslock[256]; struct xrdp_key_info keys_shiftcapslock[256]; }; /* the window manager */ struct xrdp_wm { struct xrdp_process* pro_layer; /* owner */ struct xrdp_bitmap* screen; struct xrdp_session* session; struct xrdp_painter* painter; struct xrdp_cache* cache; int palette[256]; struct xrdp_bitmap* login_window; /* generic colors */ int black; int grey; int dark_grey; int blue; int dark_blue; int white; int red; int green; int background; /* dragging info */ int dragging; int draggingx; int draggingy; int draggingcx; int draggingcy; int draggingdx; int draggingdy; int draggingorgx; int draggingorgy; int draggingxorstate; struct xrdp_bitmap* dragging_window; /* the down(clicked) button */ struct xrdp_bitmap* button_down; /* popup for combo box */ struct xrdp_bitmap* popup_wnd; /* focused window */ struct xrdp_bitmap* focused_window; /* pointer */ int current_pointer; int mouse_x; int mouse_y; /* keyboard info */ int keys[256]; /* key states 0 up 1 down*/ int caps_lock; int scroll_lock; int num_lock; /* client info */ struct xrdp_client_info* client_info; /* session log */ struct list* log; struct xrdp_bitmap* log_wnd; int login_mode; tbus login_mode_event; struct xrdp_mm* mm; struct xrdp_font* default_font; struct xrdp_keymap keymap; }; /* rdp process */ struct xrdp_process { int status; struct trans* server_trans; /* in tcp server mode */ tbus self_term_event; struct xrdp_listen* lis_layer; /* owner */ struct xrdp_session* session; /* create these when up and running */ struct xrdp_wm* wm; //int app_sck; tbus done_event; int session_id; }; /* rdp listener */ struct xrdp_listen { int status; struct trans* listen_trans; /* in tcp listen mode */ struct list* process_list; tbus pro_done_event; }; /* region */ struct xrdp_region { struct xrdp_wm* wm; /* owner */ struct list* rects; }; /* painter */ struct xrdp_painter { int rop; struct xrdp_rect* use_clip; /* nil if not using clip */ struct xrdp_rect clip; int clip_children; int bg_color; int fg_color; int mix_mode; struct xrdp_brush brush; struct xrdp_pen pen; struct xrdp_session* session; struct xrdp_wm* wm; /* owner */ struct xrdp_font* font; }; /* window or bitmap */ struct xrdp_bitmap { /* 0 = bitmap 1 = window 2 = screen 3 = button 4 = image 5 = edit 6 = label 7 = combo 8 = special */ int type; int width; int height; struct xrdp_wm* wm; /* msg 1 = click 2 = mouse move 3 = paint 100 = modal result */ /* see messages in constants.h */ int (*notify)(struct xrdp_bitmap* wnd, struct xrdp_bitmap* sender, int msg, long param1, long param2); /* for bitmap */ int bpp; int line_size; /* in bytes */ int do_not_free_data; char* data; /* for all but bitmap */ int left; int top; int pointer; int bg_color; int tab_stop; int id; char* caption1; /* for window or screen */ struct xrdp_bitmap* modal_dialog; struct xrdp_bitmap* focused_control; struct xrdp_bitmap* owner; /* window that created us */ struct xrdp_bitmap* parent; /* window contained in */ /* for modal dialog */ struct xrdp_bitmap* default_button; /* button when enter is pressed */ struct xrdp_bitmap* esc_button; /* button when esc is pressed */ /* list of child windows */ struct list* child_list; /* for edit */ int edit_pos; twchar password_char; /* for button or combo */ int state; /* for button 0 = normal 1 = down */ /* for combo */ struct list* string_list; struct list* data_list; /* for combo or popup */ int item_index; /* for popup */ struct xrdp_bitmap* popped_from; int item_height; /* crc */ int crc; }; #define NUM_FONTS 0x4e00 #define DEFAULT_FONT_NAME "sans-10.fv1" #define DEFAULT_ELEMENT_TOP 35 #define DEFAULT_BUTTON_W 60 #define DEFAULT_BUTTON_H 23 #define DEFAULT_COMBO_W 140 #define DEFAULT_COMBO_H 21 #define DEFAULT_EDIT_W 140 #define DEFAULT_EDIT_H 21 #define DEFAULT_WND_LOGIN_W 400 #define DEFAULT_WND_LOGIN_H 200 #define DEFAULT_WND_HELP_W 340 #define DEFAULT_WND_HELP_H 300 #define DEFAULT_WND_LOG_W 400 #define DEFAULT_WND_LOG_H 400 #define DEFAULT_WND_SPECIAL_H 100 /* font */ struct xrdp_font { struct xrdp_wm* wm; struct xrdp_font_char font_items[NUM_FONTS]; char name[32]; int size; int style; }; /* module */ struct xrdp_mod_data { struct list* names; struct list* values; }; struct xrdp_startup_params { char port[128]; int kill; int no_daemon; int help; int version; }; xrdp-0.6.0/xrdp/xrdp_wm.c000066400000000000000000001277411203155130500153020ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2004-2010 simple window manager */ #include "xrdp.h" /*****************************************************************************/ struct xrdp_wm* APP_CC xrdp_wm_create(struct xrdp_process* owner, struct xrdp_client_info* client_info) { struct xrdp_wm* self = (struct xrdp_wm *)NULL; char event_name[256]; int pid = 0; /* initialize (zero out) local variables: */ g_memset(event_name,0,sizeof(char) * 256); self = (struct xrdp_wm*)g_malloc(sizeof(struct xrdp_wm), 1); self->client_info = client_info; self->screen = xrdp_bitmap_create(client_info->width, client_info->height, client_info->bpp, WND_TYPE_SCREEN, self); self->screen->wm = self; self->pro_layer = owner; self->session = owner->session; pid = g_getpid(); g_snprintf(event_name, 255, "xrdp_%8.8x_wm_login_mode_event_%8.8x", pid, owner->session_id); self->login_mode_event = g_create_wait_obj(event_name); self->painter = xrdp_painter_create(self, self->session); self->cache = xrdp_cache_create(self, self->session, self->client_info); self->log = list_create(); self->log->auto_free = 1; self->mm = xrdp_mm_create(self); self->default_font = xrdp_font_create(self); /* this will use built in keymap or load from file */ get_keymaps(self->session->client_info->keylayout, &(self->keymap)); xrdp_wm_set_login_mode(self, 0); return self; } /*****************************************************************************/ void APP_CC xrdp_wm_delete(struct xrdp_wm* self) { if (self == 0) { return; } xrdp_mm_delete(self->mm); xrdp_cache_delete(self->cache); xrdp_painter_delete(self->painter); xrdp_bitmap_delete(self->screen); /* free the log */ list_delete(self->log); /* free default font */ xrdp_font_delete(self->default_font); g_delete_wait_obj(self->login_mode_event); /* free self */ g_free(self); } /*****************************************************************************/ int APP_CC xrdp_wm_send_palette(struct xrdp_wm* self) { return libxrdp_send_palette(self->session, self->palette); } /*****************************************************************************/ int APP_CC xrdp_wm_send_bell(struct xrdp_wm* self) { return libxrdp_send_bell(self->session); } /*****************************************************************************/ int APP_CC xrdp_wm_send_bitmap(struct xrdp_wm* self, struct xrdp_bitmap* bitmap, int x, int y, int cx, int cy) { return libxrdp_send_bitmap(self->session, bitmap->width, bitmap->height, bitmap->bpp, bitmap->data, x, y, cx, cy); } /*****************************************************************************/ int APP_CC xrdp_wm_set_focused(struct xrdp_wm* self, struct xrdp_bitmap* wnd) { struct xrdp_bitmap* focus_out_control; struct xrdp_bitmap* focus_in_control; if (self == 0) { return 0; } if (self->focused_window == wnd) { return 0; } focus_out_control = 0; focus_in_control = 0; if (self->focused_window != 0) { xrdp_bitmap_set_focus(self->focused_window, 0); focus_out_control = self->focused_window->focused_control; } self->focused_window = wnd; if (self->focused_window != 0) { xrdp_bitmap_set_focus(self->focused_window, 1); focus_in_control = self->focused_window->focused_control; } xrdp_bitmap_invalidate(focus_out_control, 0); xrdp_bitmap_invalidate(focus_in_control, 0); return 0; } /******************************************************************************/ static int APP_CC xrdp_wm_get_pixel(char* data, int x, int y, int width, int bpp) { int start; int shift; if (bpp == 1) { width = (width + 7) / 8; start = (y * width) + x / 8; shift = x % 8; return (data[start] & (0x80 >> shift)) != 0; } else if (bpp == 4) { width = (width + 1) / 2; start = y * width + x / 2; shift = x % 2; if (shift == 0) { return (data[start] & 0xf0) >> 4; } else { return data[start] & 0x0f; } } return 0; } /*****************************************************************************/ int APP_CC xrdp_wm_pointer(struct xrdp_wm* self, char* data, char* mask, int x, int y) { struct xrdp_pointer_item pointer_item; g_memset(&pointer_item, 0, sizeof(struct xrdp_pointer_item)); pointer_item.x = x; pointer_item.y = y; g_memcpy(pointer_item.data, data, 32 * 32 * 3); g_memcpy(pointer_item.mask, mask, 32 * 32 / 8); self->screen->pointer = xrdp_cache_add_pointer(self->cache, &pointer_item); return 0; } /*****************************************************************************/ /* returns error */ int APP_CC xrdp_wm_load_pointer(struct xrdp_wm* self, char* file_name, char* data, char* mask, int* x, int* y) { int fd; int bpp; int w; int h; int i; int j; int pixel; int palette[16]; struct stream* fs; if (!g_file_exist(file_name)) { g_writeln("xrdp_wm_load_pointer: error pointer file [%s] does not exist", file_name); return 1; } make_stream(fs); init_stream(fs, 8192); fd = g_file_open(file_name); if (fd < 1) { g_writeln("xrdp_wm_load_pointer: error loading pointer from file [%s]", file_name); return 1; } g_file_read(fd, fs->data, 8192); g_file_close(fd); in_uint8s(fs, 6); in_uint8(fs, w); in_uint8(fs, h); in_uint8s(fs, 2); in_uint16_le(fs, *x); in_uint16_le(fs, *y); in_uint8s(fs, 22); in_uint8(fs, bpp); in_uint8s(fs, 25); if (w == 32 && h == 32) { if (bpp == 1) { in_uint8a(fs, palette, 8); for (i = 0; i < 32; i++) { for (j = 0; j < 32; j++) { pixel = palette[xrdp_wm_get_pixel(fs->p, j, i, 32, 1)]; *data = pixel; data++; *data = pixel >> 8; data++; *data = pixel >> 16; data++; } } in_uint8s(fs, 128); } else if (bpp == 4) { in_uint8a(fs, palette, 64); for (i = 0; i < 32; i++) { for (j = 0; j < 32; j++) { pixel = palette[xrdp_wm_get_pixel(fs->p, j, i, 32, 1)]; *data = pixel; data++; *data = pixel >> 8; data++; *data = pixel >> 16; data++; } } in_uint8s(fs, 512); } g_memcpy(mask, fs->p, 128); /* mask */ } free_stream(fs); return 0; } /*****************************************************************************/ int APP_CC xrdp_wm_send_pointer(struct xrdp_wm* self, int cache_idx, char* data, char* mask, int x, int y) { return libxrdp_send_pointer(self->session, cache_idx, data, mask, x, y); } /*****************************************************************************/ int APP_CC xrdp_wm_set_pointer(struct xrdp_wm* self, int cache_idx) { return libxrdp_set_pointer(self->session, cache_idx); } /*****************************************************************************/ /* convert hex string to int */ unsigned int xrdp_wm_htoi (const char *ptr) { unsigned int value = 0; char ch = *ptr; while (ch == ' ' || ch == '\t') ch = *(++ptr); for (;;) { if (ch >= '0' && ch <= '9') value = (value << 4) + (ch - '0'); else if (ch >= 'A' && ch <= 'F') value = (value << 4) + (ch - 'A' + 10); else if (ch >= 'a' && ch <= 'f') value = (value << 4) + (ch - 'a' + 10); else return value; ch = *(++ptr); } } /*****************************************************************************/ int APP_CC xrdp_wm_load_static_colors(struct xrdp_wm* self) { int bindex; int gindex; int rindex; int fd; int index; char* val; struct list* names; struct list* values; char cfg_file[256]; /* initialize with defaults */ self->black = HCOLOR(self->screen->bpp,0x000000); self->grey = HCOLOR(self->screen->bpp,0xc0c0c0); self->dark_grey = HCOLOR(self->screen->bpp,0x808080); self->blue = HCOLOR(self->screen->bpp,0x0000ff); self->dark_blue = HCOLOR(self->screen->bpp,0x00007f); self->white = HCOLOR(self->screen->bpp,0xffffff); self->red = HCOLOR(self->screen->bpp,0xff0000); self->green = HCOLOR(self->screen->bpp,0x00ff00); self->background = HCOLOR(self->screen->bpp,0x000000); /* now load them from the globals in xrdp.ini if defined */ g_snprintf(cfg_file, 255, "%s/xrdp.ini", XRDP_CFG_PATH); fd = g_file_open(cfg_file); if (fd > 0) { names = list_create(); names->auto_free = 1; values = list_create(); values->auto_free = 1; if (file_read_section(fd, "globals", names, values) == 0) { for (index = 0; index < names->count; index++) { val = (char*)list_get_item(names, index); if (val != 0) { if (g_strcasecmp(val, "black") == 0) { val = (char*)list_get_item(values, index); self->black = HCOLOR(self->screen->bpp,xrdp_wm_htoi(val)); } else if (g_strcasecmp(val, "grey") == 0) { val = (char*)list_get_item(values, index); self->grey = HCOLOR(self->screen->bpp,xrdp_wm_htoi(val)); } else if (g_strcasecmp(val, "dark_grey") == 0) { val = (char*)list_get_item(values, index); self->dark_grey = HCOLOR(self->screen->bpp,xrdp_wm_htoi(val)); } else if (g_strcasecmp(val, "blue") == 0) { val = (char*)list_get_item(values, index); self->blue = HCOLOR(self->screen->bpp,xrdp_wm_htoi(val)); } else if (g_strcasecmp(val, "dark_blue") == 0) { val = (char*)list_get_item(values, index); self->dark_blue = HCOLOR(self->screen->bpp,xrdp_wm_htoi(val)); } else if (g_strcasecmp(val, "white") == 0) { val = (char*)list_get_item(values, index); self->white = HCOLOR(self->screen->bpp,xrdp_wm_htoi(val)); } else if (g_strcasecmp(val, "red") == 0) { val = (char*)list_get_item(values, index); self->red = HCOLOR(self->screen->bpp,xrdp_wm_htoi(val)); } else if (g_strcasecmp(val, "green") == 0) { val = (char*)list_get_item(values, index); self->green = HCOLOR(self->screen->bpp,xrdp_wm_htoi(val)); } else if (g_strcasecmp(val, "background") == 0) { val = (char*)list_get_item(values, index); self->background = HCOLOR(self->screen->bpp,xrdp_wm_htoi(val)); } } } } list_delete(names); list_delete(values); g_file_close(fd); } else { g_writeln("xrdp_wm_load_static_colors: Could not read xrdp.ini file %s", cfg_file); } if (self->screen->bpp == 8) { /* rgb332 */ for (bindex = 0; bindex < 4; bindex++) { for (gindex = 0; gindex < 8; gindex++) { for (rindex = 0; rindex < 8; rindex++) { self->palette[(bindex << 6) | (gindex << 3) | rindex] = (((rindex << 5) | (rindex << 2) | (rindex >> 1)) << 16) | (((gindex << 5) | (gindex << 2) | (gindex >> 1)) << 8) | ((bindex << 6) | (bindex << 4) | (bindex << 2) | (bindex)); } } } xrdp_wm_send_palette(self); } return 0; } /*****************************************************************************/ /* returns error */ int APP_CC xrdp_wm_load_static_pointers(struct xrdp_wm* self) { struct xrdp_pointer_item pointer_item; char file_path[256]; DEBUG(("sending cursor")); g_snprintf(file_path, 255, "%s/cursor1.cur", XRDP_SHARE_PATH); g_memset(&pointer_item, 0, sizeof(pointer_item)); xrdp_wm_load_pointer(self, file_path, pointer_item.data, pointer_item.mask, &pointer_item.x, &pointer_item.y); xrdp_cache_add_pointer_static(self->cache, &pointer_item, 1); DEBUG(("sending cursor")); g_snprintf(file_path, 255, "%s/cursor0.cur", XRDP_SHARE_PATH); g_memset(&pointer_item, 0, sizeof(pointer_item)); xrdp_wm_load_pointer(self, file_path, pointer_item.data, pointer_item.mask, &pointer_item.x, &pointer_item.y); xrdp_cache_add_pointer_static(self->cache, &pointer_item, 0); return 0; } /*****************************************************************************/ int APP_CC xrdp_wm_init(struct xrdp_wm* self) { int fd; int index; struct list* names; struct list* values; char* q; char* r; char section_name[256]; char cfg_file[256]; xrdp_wm_load_static_colors(self); xrdp_wm_load_static_pointers(self); self->screen->bg_color = self->background; if (self->session->client_info->rdp_autologin) { g_snprintf(cfg_file, 255, "%s/xrdp.ini", XRDP_CFG_PATH); fd = g_file_open(cfg_file); /* xrdp.ini */ if (fd > 0) { names = list_create(); names->auto_free = 1; values = list_create(); values->auto_free = 1; g_strncpy(section_name, self->session->client_info->domain, 255); if (section_name[0] == 0) { /* if no doamin is passed, use the first item in the xrdp.ini file thats not named 'globals' */ file_read_sections(fd, names); for (index = 0; index < names->count; index++) { q = (char*)list_get_item(names, index); if (g_strncasecmp("globals", q, 8) != 0) { g_strncpy(section_name, q, 255); break; } } } list_clear(names); if (file_read_section(fd, section_name, names, values) == 0) { for (index = 0; index < names->count; index++) { q = (char*)list_get_item(names, index); r = (char*)list_get_item(values, index); if (g_strncmp("password", q, 255) == 0) { /* if the password has been asked for by the module, use what the client says. if the password has been manually set in the config, use that instead of what the client says. */ if (g_strncmp("ask", r, 3) == 0) { r = self->session->client_info->password; } } else if (g_strncmp("username", q, 255) == 0) { /* if the username has been asked for by the module, use what the client says. if the username has been manually set in the config, use that instead of what the client says. */ if (g_strncmp("ask", r, 3) == 0) { r = self->session->client_info->username; } } list_add_item(self->mm->login_names, (long)g_strdup(q)); list_add_item(self->mm->login_values, (long)g_strdup(r)); } xrdp_wm_set_login_mode(self, 2); } list_delete(names); list_delete(values); g_file_close(fd); } else { g_writeln("xrdp_wm_init: Could not read xrdp.ini file %s", cfg_file); } } else { xrdp_login_wnd_create(self); /* clear screen */ xrdp_bitmap_invalidate(self->screen, 0); xrdp_wm_set_focused(self, self->login_window); xrdp_wm_set_login_mode(self, 1); } return 0; } /*****************************************************************************/ /* returns the number for rects visible for an area relative to a drawable */ /* putting the rects in region */ int APP_CC xrdp_wm_get_vis_region(struct xrdp_wm* self, struct xrdp_bitmap* bitmap, int x, int y, int cx, int cy, struct xrdp_region* region, int clip_children) { int i; struct xrdp_bitmap* p; struct xrdp_rect a; struct xrdp_rect b; /* area we are drawing */ MAKERECT(a, bitmap->left + x, bitmap->top + y, cx, cy); p = bitmap->parent; while (p != 0) { RECTOFFSET(a, p->left, p->top); p = p->parent; } a.left = MAX(self->screen->left, a.left); a.top = MAX(self->screen->top, a.top); a.right = MIN(self->screen->left + self->screen->width, a.right); a.bottom = MIN(self->screen->top + self->screen->height, a.bottom); xrdp_region_add_rect(region, &a); if (clip_children) { /* loop through all windows in z order */ for (i = 0; i < self->screen->child_list->count; i++) { p = (struct xrdp_bitmap*)list_get_item(self->screen->child_list, i); if (p == bitmap || p == bitmap->parent) { return 0; } MAKERECT(b, p->left, p->top, p->width, p->height); xrdp_region_subtract_rect(region, &b); } } return 0; } /*****************************************************************************/ /* return the window at x, y on the screen */ static struct xrdp_bitmap* APP_CC xrdp_wm_at_pos(struct xrdp_bitmap* wnd, int x, int y, struct xrdp_bitmap** wnd1) { int i; struct xrdp_bitmap* p; struct xrdp_bitmap* q; /* loop through all windows in z order */ for (i = 0; i < wnd->child_list->count; i++) { p = (struct xrdp_bitmap*)list_get_item(wnd->child_list, i); if (x >= p->left && y >= p->top && x < p->left + p->width && y < p->top + p->height) { if (wnd1 != 0) { *wnd1 = p; } q = xrdp_wm_at_pos(p, x - p->left, y - p->top, 0); if (q == 0) { return p; } else { return q; } } } return 0; } /*****************************************************************************/ static int APP_CC xrdp_wm_xor_pat(struct xrdp_wm* self, int x, int y, int cx, int cy) { self->painter->clip_children = 0; self->painter->rop = 0x5a; xrdp_painter_begin_update(self->painter); self->painter->use_clip = 0; self->painter->mix_mode = 1; self->painter->brush.pattern[0] = 0xaa; self->painter->brush.pattern[1] = 0x55; self->painter->brush.pattern[2] = 0xaa; self->painter->brush.pattern[3] = 0x55; self->painter->brush.pattern[4] = 0xaa; self->painter->brush.pattern[5] = 0x55; self->painter->brush.pattern[6] = 0xaa; self->painter->brush.pattern[7] = 0x55; self->painter->brush.x_orgin = 0; self->painter->brush.x_orgin = 0; self->painter->brush.style = 3; self->painter->bg_color = self->black; self->painter->fg_color = self->white; /* top */ xrdp_painter_fill_rect(self->painter, self->screen, x, y, cx, 5); /* bottom */ xrdp_painter_fill_rect(self->painter, self->screen, x, y + (cy - 5), cx, 5); /* left */ xrdp_painter_fill_rect(self->painter, self->screen, x, y + 5, 5, cy - 10); /* right */ xrdp_painter_fill_rect(self->painter, self->screen, x + (cx - 5), y + 5, 5, cy - 10); xrdp_painter_end_update(self->painter); self->painter->rop = 0xcc; self->painter->clip_children = 1; self->painter->mix_mode = 0; return 0; } /*****************************************************************************/ /* this don't are about nothing, just copy the bits */ /* no clipping rects, no windows in the way, nothing */ static int APP_CC xrdp_wm_bitblt(struct xrdp_wm* self, struct xrdp_bitmap* dst, int dx, int dy, struct xrdp_bitmap* src, int sx, int sy, int sw, int sh, int rop) { // int i; // int line_size; // int Bpp; // char* s; // char* d; // if (sw <= 0 || sh <= 0) // return 0; if (self->screen == dst && self->screen == src) { /* send a screen blt */ // Bpp = (dst->bpp + 7) / 8; // line_size = sw * Bpp; // s = src->data + (sy * src->width + sx) * Bpp; // d = dst->data + (dy * dst->width + dx) * Bpp; // for (i = 0; i < sh; i++) // { // //g_memcpy(d, s, line_size); // s += src->width * Bpp; // d += dst->width * Bpp; // } libxrdp_orders_init(self->session); libxrdp_orders_screen_blt(self->session, dx, dy, sw, sh, sx, sy, rop, 0); libxrdp_orders_send(self->session); } return 0; } /*****************************************************************************/ /* return true is rect is totaly exposed going in reverse z order */ /* from wnd up */ static int APP_CC xrdp_wm_is_rect_vis(struct xrdp_wm* self, struct xrdp_bitmap* wnd, struct xrdp_rect* rect) { struct xrdp_rect wnd_rect; struct xrdp_bitmap* b; int i;; /* if rect is part off screen */ if (rect->left < 0) { return 0; } if (rect->top < 0) { return 0; } if (rect->right >= self->screen->width) { return 0; } if (rect->bottom >= self->screen->height) { return 0; } i = list_index_of(self->screen->child_list, (long)wnd); i--; while (i >= 0) { b = (struct xrdp_bitmap*)list_get_item(self->screen->child_list, i); MAKERECT(wnd_rect, b->left, b->top, b->width, b->height); if (rect_intersect(rect, &wnd_rect, 0)) { return 0; } i--; } return 1; } /*****************************************************************************/ static int APP_CC xrdp_wm_move_window(struct xrdp_wm* self, struct xrdp_bitmap* wnd, int dx, int dy) { struct xrdp_rect rect1; struct xrdp_rect rect2; struct xrdp_region* r; int i; MAKERECT(rect1, wnd->left, wnd->top, wnd->width, wnd->height); if (xrdp_wm_is_rect_vis(self, wnd, &rect1)) { rect2 = rect1; RECTOFFSET(rect2, dx, dy); if (xrdp_wm_is_rect_vis(self, wnd, &rect2)) { /* if both src and dst are unobscured, we can do a bitblt move */ xrdp_wm_bitblt(self, self->screen, wnd->left + dx, wnd->top + dy, self->screen, wnd->left, wnd->top, wnd->width, wnd->height, 0xcc); wnd->left += dx; wnd->top += dy; r = xrdp_region_create(self); xrdp_region_add_rect(r, &rect1); xrdp_region_subtract_rect(r, &rect2); i = 0; while (xrdp_region_get_rect(r, i, &rect1) == 0) { xrdp_bitmap_invalidate(self->screen, &rect1); i++; } xrdp_region_delete(r); return 0; } } wnd->left += dx; wnd->top += dy; xrdp_bitmap_invalidate(self->screen, &rect1); xrdp_bitmap_invalidate(wnd, 0); return 0; } /*****************************************************************************/ static int APP_CC xrdp_wm_undraw_dragging_box(struct xrdp_wm* self, int do_begin_end) { int boxx; int boxy; if (self == 0) { return 0; } if (self->dragging) { if (self->draggingxorstate) { if (do_begin_end) { xrdp_painter_begin_update(self->painter); } boxx = self->draggingx - self->draggingdx; boxy = self->draggingy - self->draggingdy; xrdp_wm_xor_pat(self, boxx, boxy, self->draggingcx, self->draggingcy); self->draggingxorstate = 0; if (do_begin_end) { xrdp_painter_end_update(self->painter); } } } return 0; } /*****************************************************************************/ static int APP_CC xrdp_wm_draw_dragging_box(struct xrdp_wm* self, int do_begin_end) { int boxx; int boxy; if (self == 0) { return 0; } if (self->dragging) { if (!self->draggingxorstate) { if (do_begin_end) { xrdp_painter_begin_update(self->painter); } boxx = self->draggingx - self->draggingdx; boxy = self->draggingy - self->draggingdy; xrdp_wm_xor_pat(self, boxx, boxy, self->draggingcx, self->draggingcy); self->draggingxorstate = 1; if (do_begin_end) { xrdp_painter_end_update(self->painter); } } } return 0; } /*****************************************************************************/ int APP_CC xrdp_wm_mouse_move(struct xrdp_wm* self, int x, int y) { struct xrdp_bitmap* b; if (self == 0) { return 0; } if (x < 0) { x = 0; } if (y < 0) { y = 0; } if (x >= self->screen->width) { x = self->screen->width; } if (y >= self->screen->height) { y = self->screen->height; } self->mouse_x = x; self->mouse_y = y; if (self->dragging) { xrdp_painter_begin_update(self->painter); xrdp_wm_undraw_dragging_box(self, 0); self->draggingx = x; self->draggingy = y; xrdp_wm_draw_dragging_box(self, 0); xrdp_painter_end_update(self->painter); return 0; } b = xrdp_wm_at_pos(self->screen, x, y, 0); if (b == 0) /* if b is null, the movment must be over the screen */ { if (self->screen->pointer != self->current_pointer) { xrdp_wm_set_pointer(self, self->screen->pointer); self->current_pointer = self->screen->pointer; } if (self->mm->mod != 0) /* if screen is mod controled */ { if (self->mm->mod->mod_event != 0) { self->mm->mod->mod_event(self->mm->mod, WM_MOUSEMOVE, x, y, 0, 0); } } } if (self->button_down != 0) { if (b == self->button_down && self->button_down->state == 0) { self->button_down->state = 1; xrdp_bitmap_invalidate(self->button_down, 0); } else if (b != self->button_down) { self->button_down->state = 0; xrdp_bitmap_invalidate(self->button_down, 0); } } if (b != 0) { if (!self->dragging) { if (b->pointer != self->current_pointer) { xrdp_wm_set_pointer(self, b->pointer); self->current_pointer = b->pointer; } xrdp_bitmap_def_proc(b, WM_MOUSEMOVE, xrdp_bitmap_from_screenx(b, x), xrdp_bitmap_from_screeny(b, y)); if (self->button_down == 0) { if (b->notify != 0) { b->notify(b->owner, b, 2, x, y); } } } } return 0; } /*****************************************************************************/ static int APP_CC xrdp_wm_clear_popup(struct xrdp_wm* self) { int i; struct xrdp_rect rect; //struct xrdp_bitmap* b; //b = 0; if (self->popup_wnd != 0) { //b = self->popup_wnd->popped_from; i = list_index_of(self->screen->child_list, (long)self->popup_wnd); list_remove_item(self->screen->child_list, i); MAKERECT(rect, self->popup_wnd->left, self->popup_wnd->top, self->popup_wnd->width, self->popup_wnd->height); xrdp_bitmap_invalidate(self->screen, &rect); xrdp_bitmap_delete(self->popup_wnd); } //xrdp_wm_set_focused(self, b->parent); return 0; } /*****************************************************************************/ int APP_CC xrdp_wm_mouse_click(struct xrdp_wm* self, int x, int y, int but, int down) { struct xrdp_bitmap* control; struct xrdp_bitmap* focus_out_control; struct xrdp_bitmap* wnd; int newx; int newy; int oldx; int oldy; if (self == 0) { return 0; } if (x < 0) { x = 0; } if (y < 0) { y = 0; } if (x >= self->screen->width) { x = self->screen->width; } if (y >= self->screen->height) { y = self->screen->height; } if (self->dragging && but == 1 && !down && self->dragging_window != 0) { /* if done dragging */ self->draggingx = x; self->draggingy = y; newx = self->draggingx - self->draggingdx; newy = self->draggingy - self->draggingdy; oldx = self->dragging_window->left; oldy = self->dragging_window->top; /* draw xor box one more time */ if (self->draggingxorstate) { xrdp_wm_xor_pat(self, newx, newy, self->draggingcx, self->draggingcy); } self->draggingxorstate = 0; /* move screen to new location */ xrdp_wm_move_window(self, self->dragging_window, newx - oldx, newy - oldy); self->dragging_window = 0; self->dragging = 0; } wnd = 0; control = xrdp_wm_at_pos(self->screen, x, y, &wnd); if (control == 0) { if (self->mm->mod != 0) /* if screen is mod controled */ { if (self->mm->mod->mod_event != 0) { if (but == 1 && down) { self->mm->mod->mod_event(self->mm->mod, WM_LBUTTONDOWN, x, y, 0, 0); } else if (but == 1 && !down) { self->mm->mod->mod_event(self->mm->mod, WM_LBUTTONUP, x, y, 0, 0); } if (but == 2 && down) { self->mm->mod->mod_event(self->mm->mod, WM_RBUTTONDOWN, x, y, 0, 0); } else if (but == 2 && !down) { self->mm->mod->mod_event(self->mm->mod, WM_RBUTTONUP, x, y, 0, 0); } if (but == 3 && down) { self->mm->mod->mod_event(self->mm->mod, WM_BUTTON3DOWN, x, y, 0, 0); } else if (but == 3 && !down) { self->mm->mod->mod_event(self->mm->mod, WM_BUTTON3UP, x, y, 0, 0); } if (but == 4) { self->mm->mod->mod_event(self->mm->mod, WM_BUTTON4DOWN, self->mouse_x, self->mouse_y, 0, 0); self->mm->mod->mod_event(self->mm->mod, WM_BUTTON4UP, self->mouse_x, self->mouse_y, 0, 0); } if (but == 5) { self->mm->mod->mod_event(self->mm->mod, WM_BUTTON5DOWN, self->mouse_x, self->mouse_y, 0, 0); self->mm->mod->mod_event(self->mm->mod, WM_BUTTON5UP, self->mouse_x, self->mouse_y, 0, 0); } } } } if (self->popup_wnd != 0) { if (self->popup_wnd == control && !down) { xrdp_bitmap_def_proc(self->popup_wnd, WM_LBUTTONUP, x, y); xrdp_wm_clear_popup(self); self->button_down = 0; return 0; } else if (self->popup_wnd != control && down) { xrdp_wm_clear_popup(self); self->button_down = 0; return 0; } } if (control != 0) { if (wnd != 0) { if (wnd->modal_dialog != 0) /* if window has a modal dialog */ { return 0; } if (control == wnd) { } else if (control->tab_stop) { focus_out_control = wnd->focused_control; wnd->focused_control = control; xrdp_bitmap_invalidate(focus_out_control, 0); xrdp_bitmap_invalidate(control, 0); } } if ((control->type == WND_TYPE_BUTTON || control->type == WND_TYPE_COMBO) && but == 1 && !down && self->button_down == control) { /* if clicking up on a button that was clicked down */ self->button_down = 0; control->state = 0; xrdp_bitmap_invalidate(control, 0); if (control->parent != 0) { if (control->parent->notify != 0) { /* control can be invalid after this */ control->parent->notify(control->owner, control, 1, x, y); } } } else if ((control->type == WND_TYPE_BUTTON || control->type == WND_TYPE_COMBO) && but == 1 && down) { /* if clicking down on a button or combo */ self->button_down = control; control->state = 1; xrdp_bitmap_invalidate(control, 0); if (control->type == WND_TYPE_COMBO) { xrdp_wm_pu(self, control); } } else if (but == 1 && down) { if (self->popup_wnd == 0) { xrdp_wm_set_focused(self, wnd); if (control->type == WND_TYPE_WND && y < (control->top + 21)) { /* if dragging */ if (self->dragging) /* rarely happens */ { newx = self->draggingx - self->draggingdx; newy = self->draggingy - self->draggingdy; if (self->draggingxorstate) { xrdp_wm_xor_pat(self, newx, newy, self->draggingcx, self->draggingcy); } self->draggingxorstate = 0; } self->dragging = 1; self->dragging_window = control; self->draggingorgx = control->left; self->draggingorgy = control->top; self->draggingx = x; self->draggingy = y; self->draggingdx = x - control->left; self->draggingdy = y - control->top; self->draggingcx = control->width; self->draggingcy = control->height; } } } } else { xrdp_wm_set_focused(self, 0); } /* no matter what, mouse is up, reset button_down */ if (but == 1 && !down && self->button_down != 0) { self->button_down = 0; } return 0; } /*****************************************************************************/ int APP_CC xrdp_wm_key(struct xrdp_wm* self, int device_flags, int scan_code) { int msg; struct xrdp_key_info* ki; /*g_printf("count %d\n", self->key_down_list->count);*/ scan_code = scan_code % 128; if (self->popup_wnd != 0) { xrdp_wm_clear_popup(self); return 0; } if (device_flags & KBD_FLAG_UP) /* 0x8000 */ { self->keys[scan_code] = 0; msg = WM_KEYUP; } else /* key down */ { self->keys[scan_code] = 1 | device_flags; msg = WM_KEYDOWN; switch (scan_code) { case 58: self->caps_lock = !self->caps_lock; break; /* caps lock */ case 69: self->num_lock = !self->num_lock; break; /* num lock */ case 70: self->scroll_lock = !self->scroll_lock; break; /* scroll lock */ } } if (self->mm->mod != 0) { if (self->mm->mod->mod_event != 0) { ki = get_key_info_from_scan_code (device_flags, scan_code, self->keys, self->caps_lock, self->num_lock, self->scroll_lock, &(self->keymap)); if (ki != 0) { self->mm->mod->mod_event(self->mm->mod, msg, ki->chr, ki->sym, scan_code, device_flags); } } } else if (self->focused_window != 0) { xrdp_bitmap_def_proc(self->focused_window, msg, scan_code, device_flags); } return 0; } /*****************************************************************************/ /* happens when client gets focus and sends key modifier info */ int APP_CC xrdp_wm_key_sync(struct xrdp_wm* self, int device_flags, int key_flags) { self->num_lock = 0; self->scroll_lock = 0; self->caps_lock = 0; if (key_flags & 1) { self->scroll_lock = 1; } if (key_flags & 2) { self->num_lock = 1; } if (key_flags & 4) { self->caps_lock = 1; } if (self->mm->mod != 0) { if (self->mm->mod->mod_event != 0) { self->mm->mod->mod_event(self->mm->mod, 17, key_flags, device_flags, key_flags, device_flags); } } return 0; } /*****************************************************************************/ int APP_CC xrdp_wm_pu(struct xrdp_wm* self, struct xrdp_bitmap* control) { int x; int y; if (self == 0) { return 0; } if (control == 0) { return 0; } self->popup_wnd = xrdp_bitmap_create(control->width, DEFAULT_WND_SPECIAL_H, self->screen->bpp, WND_TYPE_SPECIAL, self); self->popup_wnd->popped_from = control; self->popup_wnd->parent = self->screen; self->popup_wnd->owner = self->screen; x = xrdp_bitmap_to_screenx(control, 0); y = xrdp_bitmap_to_screeny(control, 0); self->popup_wnd->left = x; self->popup_wnd->top = y + control->height; self->popup_wnd->item_index = control->item_index; list_insert_item(self->screen->child_list, 0, (long)self->popup_wnd); xrdp_bitmap_invalidate(self->popup_wnd, 0); return 0; } /*****************************************************************************/ static int APP_CC xrdp_wm_process_input_mouse(struct xrdp_wm* self, int device_flags, int x, int y) { DEBUG(("mouse event flags %4.4x x %d y %d", device_flags, x, y)); if (device_flags & MOUSE_FLAG_MOVE) /* 0x0800 */ { xrdp_wm_mouse_move(self, x, y); } if (device_flags & MOUSE_FLAG_BUTTON1) /* 0x1000 */ { if (device_flags & MOUSE_FLAG_DOWN) /* 0x8000 */ { xrdp_wm_mouse_click(self, x, y, 1, 1); } else { xrdp_wm_mouse_click(self, x, y, 1, 0); } } if (device_flags & MOUSE_FLAG_BUTTON2) /* 0x2000 */ { if (device_flags & MOUSE_FLAG_DOWN) /* 0x8000 */ { xrdp_wm_mouse_click(self, x, y, 2, 1); } else { xrdp_wm_mouse_click(self, x, y, 2, 0); } } if (device_flags & MOUSE_FLAG_BUTTON3) /* 0x4000 */ { if (device_flags & MOUSE_FLAG_DOWN) /* 0x8000 */ { xrdp_wm_mouse_click(self, x, y, 3, 1); } else { xrdp_wm_mouse_click(self, x, y, 3, 0); } } if (device_flags == MOUSE_FLAG_BUTTON4 || /* 0x0280 */ device_flags == 0x0278) { xrdp_wm_mouse_click(self, 0, 0, 4, 0); } if (device_flags == MOUSE_FLAG_BUTTON5 || /* 0x0380 */ device_flags == 0x0388) { xrdp_wm_mouse_click(self, 0, 0, 5, 0); } return 0; } /******************************************************************************/ /* param1 = MAKELONG(channel_id, flags) param2 = size param3 = pointer to data param4 = total size */ static int APP_CC xrdp_wm_process_channel_data(struct xrdp_wm* self, tbus param1, tbus param2, tbus param3, tbus param4) { int rv; rv = 1; if (self->mm->mod != 0) { if (self->mm->sesman_controlled) { rv = xrdp_mm_process_channel_data(self->mm, param1, param2, param3, param4); } else { if (self->mm->mod->mod_event != 0) { rv = self->mm->mod->mod_event(self->mm->mod, 0x5555, param1, param2, param3, param4); } } } return rv; } /******************************************************************************/ /* this is the callbacks comming from libxrdp.so */ int DEFAULT_CC callback(long id, int msg, long param1, long param2, long param3, long param4) { int rv; struct xrdp_wm* wm; struct xrdp_rect rect; if (id == 0) /* "id" should be "struct xrdp_process*" as long */ { return 0; } wm = ((struct xrdp_process*)id)->wm; if (wm == 0) { return 0; } rv = 0; switch (msg) { case 0: /* RDP_INPUT_SYNCHRONIZE */ rv = xrdp_wm_key_sync(wm, param3, param1); break; case 4: /* RDP_INPUT_SCANCODE */ rv = xrdp_wm_key(wm, param3, param1); break; case 0x8001: /* RDP_INPUT_MOUSE */ rv = xrdp_wm_process_input_mouse(wm, param3, param1, param2); break; case 0x4444: /* invalidate, this is not from RDP_DATA_PDU_INPUT */ /* like the rest, its from RDP_PDU_DATA with code 33 */ /* its the rdp client asking for a screen update */ MAKERECT(rect, param1, param2, param3, param4); rv = xrdp_bitmap_invalidate(wm->screen, &rect); break; case 0x5555: /* called from xrdp_channel.c, channel data has come in, pass it to module if there is one */ rv = xrdp_wm_process_channel_data(wm, param1, param2, param3, param4); break; } return rv; } /******************************************************************************/ /* returns error */ /* this gets called when there is nothing on any socket */ static int APP_CC xrdp_wm_login_mode_changed(struct xrdp_wm* self) { if (self == 0) { return 0; } if (self->login_mode == 0) { /* this is the inital state of the login window */ xrdp_wm_set_login_mode(self, 1); /* put the wm in login mode */ list_clear(self->log); xrdp_wm_delete_all_childs(self); self->dragging = 0; xrdp_wm_init(self); } else if (self->login_mode == 2) { xrdp_wm_set_login_mode(self, 3); /* put the wm in connected mode */ xrdp_wm_delete_all_childs(self); self->dragging = 0; xrdp_mm_connect(self->mm); } else if (self->login_mode == 10) { xrdp_wm_delete_all_childs(self); self->dragging = 0; xrdp_wm_set_login_mode(self, 11); } return 0; } /*****************************************************************************/ /* this is the log windows nofity function */ static int DEFAULT_CC xrdp_wm_log_wnd_notify(struct xrdp_bitmap* wnd, struct xrdp_bitmap* sender, int msg, long param1, long param2) { struct xrdp_painter* painter; struct xrdp_wm* wm; struct xrdp_rect rect; int index; char* text; if (wnd == 0) { return 0; } if (sender == 0) { return 0; } if (wnd->owner == 0) { return 0; } wm = wnd->wm; if (msg == 1) /* click */ { if (sender->id == 1) /* ok button */ { /* close the log window */ MAKERECT(rect, wnd->left, wnd->top, wnd->width, wnd->height); xrdp_bitmap_delete(wnd); xrdp_bitmap_invalidate(wm->screen, &rect); /* if module is gone, reset the session when ok is clicked */ if (wm->mm->mod_handle == 0) { /* make sure autologin is off */ wm->session->client_info->rdp_autologin = 0; xrdp_wm_set_login_mode(wm, 0); /* reset session */ } } } else if (msg == WM_PAINT) /* 3 */ { painter = (struct xrdp_painter*)param1; if (painter != 0) { painter->fg_color = wnd->wm->black; for (index = 0; index < wnd->wm->log->count; index++) { text = (char*)list_get_item(wnd->wm->log, index); xrdp_painter_draw_text(painter, wnd, 10, 30 + index * 15, text); } } } return 0; } /*****************************************************************************/ int APP_CC xrdp_wm_log_msg(struct xrdp_wm* self, char* msg) { struct xrdp_bitmap* but; int w; int h; int xoffset; int yoffset; list_add_item(self->log, (long)g_strdup(msg)); if (self->log_wnd == 0) { w = DEFAULT_WND_LOG_W; h = DEFAULT_WND_LOG_H; xoffset = 10; yoffset = 10; if (self->screen->width < w) { w = self->screen->width - 4; xoffset = 2; } if (self->screen->height < h) { h = self->screen->height - 4; yoffset = 2; } /* log window */ self->log_wnd = xrdp_bitmap_create(w, h, self->screen->bpp, WND_TYPE_WND, self); list_add_item(self->screen->child_list, (long)self->log_wnd); self->log_wnd->parent = self->screen; self->log_wnd->owner = self->screen; self->log_wnd->bg_color = self->grey; self->log_wnd->left = xoffset; self->log_wnd->top = yoffset; set_string(&(self->log_wnd->caption1), "Connection Log"); /* ok button */ but = xrdp_bitmap_create(DEFAULT_BUTTON_W, DEFAULT_BUTTON_H, self->screen->bpp, WND_TYPE_BUTTON, self); list_insert_item(self->log_wnd->child_list, 0, (long)but); but->parent = self->log_wnd; but->owner = self->log_wnd; but->left = (w - DEFAULT_BUTTON_W) - xoffset; but->top = (h - DEFAULT_BUTTON_H) - yoffset; but->id = 1; but->tab_stop = 1; set_string(&but->caption1, "OK"); self->log_wnd->focused_control = but; /* set notify function */ self->log_wnd->notify = xrdp_wm_log_wnd_notify; } xrdp_wm_set_focused(self, self->log_wnd); xrdp_bitmap_invalidate(self->log_wnd, 0); g_sleep(100); return 0; } /*****************************************************************************/ int APP_CC xrdp_wm_get_wait_objs(struct xrdp_wm* self, tbus* robjs, int* rc, tbus* wobjs, int* wc, int* timeout) { int i; if (self == 0) { return 0; } i = *rc; robjs[i++] = self->login_mode_event; *rc = i; return xrdp_mm_get_wait_objs(self->mm, robjs, rc, wobjs, wc, timeout); } /******************************************************************************/ int APP_CC xrdp_wm_check_wait_objs(struct xrdp_wm* self) { int rv; if (self == 0) { return 0; } rv = 0; if (g_is_wait_obj_set(self->login_mode_event)) { g_reset_wait_obj(self->login_mode_event); xrdp_wm_login_mode_changed(self); } if (rv == 0) { rv = xrdp_mm_check_wait_objs(self->mm); } return rv; } /*****************************************************************************/ int APP_CC xrdp_wm_set_login_mode(struct xrdp_wm* self, int login_mode) { self->login_mode = login_mode; g_set_wait_obj(self->login_mode_event); return 0; } xrdp-0.6.0/xrdp/xrdpwin.c000066400000000000000000000400441203155130500153030ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2004-2012 main program */ #if defined(_WIN32) #include #endif #include "xrdp.h" static struct xrdp_listen* g_listen = 0; static long g_threadid = 0; /* main threadid */ #if defined(_WIN32) static SERVICE_STATUS_HANDLE g_ssh = 0; static SERVICE_STATUS g_service_status; #endif static long g_sync_mutex = 0; static long g_sync1_mutex = 0; static tbus g_term_event = 0; static tbus g_sync_event = 0; /* syncronize stuff */ static int g_sync_command = 0; static long g_sync_result = 0; static long g_sync_param1 = 0; static long g_sync_param2 = 0; static long (*g_sync_func)(long param1, long param2); /*****************************************************************************/ long APP_CC g_xrdp_sync(long (*sync_func)(long param1, long param2), long sync_param1, long sync_param2) { long sync_result; int sync_command; if (tc_threadid_equal(tc_get_threadid(), g_threadid)) { /* this is the main thread, call the function directly */ sync_result = sync_func(sync_param1, sync_param2); } else { tc_mutex_lock(g_sync1_mutex); tc_mutex_lock(g_sync_mutex); g_sync_param1 = sync_param1; g_sync_param2 = sync_param2; g_sync_func = sync_func; g_sync_command = 100; tc_mutex_unlock(g_sync_mutex); g_set_wait_obj(g_sync_event); do { g_sleep(100); tc_mutex_lock(g_sync_mutex); sync_command = g_sync_command; sync_result = g_sync_result; tc_mutex_unlock(g_sync_mutex); } while (sync_command != 0); tc_mutex_unlock(g_sync1_mutex); } return sync_result; } /*****************************************************************************/ void DEFAULT_CC xrdp_shutdown(int sig) { tbus threadid; threadid = tc_get_threadid(); g_writeln("shutting down"); g_writeln("signal %d threadid %p", sig, threadid); if (!g_is_wait_obj_set(g_term_event)) { g_set_wait_obj(g_term_event); } } /*****************************************************************************/ int APP_CC g_is_term(void) { return g_is_wait_obj_set(g_term_event); } /*****************************************************************************/ void APP_CC g_set_term(int in_val) { if (in_val) { g_set_wait_obj(g_term_event); } else { g_reset_wait_obj(g_term_event); } } /*****************************************************************************/ tbus APP_CC g_get_term_event(void) { return g_term_event; } /*****************************************************************************/ tbus APP_CC g_get_sync_event(void) { return g_sync_event; } /*****************************************************************************/ void DEFAULT_CC pipe_sig(int sig_num) { /* do nothing */ g_writeln("got SIGPIPE(%d)", sig_num); } /*****************************************************************************/ void APP_CC g_loop(void) { tc_mutex_lock(g_sync_mutex); if (g_sync_command != 0) { if (g_sync_func != 0) { if (g_sync_command == 100) { g_sync_result = g_sync_func(g_sync_param1, g_sync_param2); } } g_sync_command = 0; } tc_mutex_unlock(g_sync_mutex); } /* win32 service control functions */ #if defined(_WIN32) /*****************************************************************************/ VOID WINAPI MyHandler(DWORD fdwControl) { if (g_ssh == 0) { return; } if (fdwControl == SERVICE_CONTROL_STOP) { g_service_status.dwCurrentState = SERVICE_STOP_PENDING; g_set_term(1); } else if (fdwControl == SERVICE_CONTROL_PAUSE) { /* shouldn't happen */ } else if (fdwControl == SERVICE_CONTROL_CONTINUE) { /* shouldn't happen */ } else if (fdwControl == SERVICE_CONTROL_INTERROGATE) { } else if (fdwControl == SERVICE_CONTROL_SHUTDOWN) { g_service_status.dwCurrentState = SERVICE_STOP_PENDING; g_set_term(1); } SetServiceStatus(g_ssh, &g_service_status); } /*****************************************************************************/ static void DEFAULT_CC log_event(HANDLE han, char* msg) { ReportEvent(han, EVENTLOG_INFORMATION_TYPE, 0, 0, 0, 1, 0, &msg, 0); } /*****************************************************************************/ VOID WINAPI MyServiceMain(DWORD dwArgc, LPTSTR* lpszArgv) { WSADATA w; char text[256]; int pid; //HANDLE event_han; // int fd; // char text[256]; // fd = g_file_open("c:\\temp\\xrdp\\log.txt"); // g_file_write(fd, "hi\r\n", 4); //event_han = RegisterEventSource(0, "xrdp"); //log_event(event_han, "hi xrdp log"); g_threadid = tc_get_threadid(); g_set_current_dir("c:\\temp\\xrdp"); g_listen = 0; WSAStartup(2, &w); g_sync_mutex = tc_mutex_create(); g_sync1_mutex = tc_mutex_create(); pid = g_getpid(); g_snprintf(text, 255, "xrdp_%8.8x_main_term", pid); g_term_event = g_create_wait_obj(text); g_snprintf(text, 255, "xrdp_%8.8x_main_sync", pid); g_sync_event = g_create_wait_obj(text); g_memset(&g_service_status, 0, sizeof(SERVICE_STATUS)); g_service_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS; g_service_status.dwCurrentState = SERVICE_RUNNING; g_service_status.dwControlsAccepted = SERVICE_CONTROL_INTERROGATE | SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN; g_service_status.dwWin32ExitCode = NO_ERROR; g_service_status.dwServiceSpecificExitCode = 0; g_service_status.dwCheckPoint = 0; g_service_status.dwWaitHint = 0; // g_sprintf(text, "calling RegisterServiceCtrlHandler\r\n"); // g_file_write(fd, text, g_strlen(text)); g_ssh = RegisterServiceCtrlHandler("xrdp", MyHandler); if (g_ssh != 0) { // g_sprintf(text, "ok\r\n"); // g_file_write(fd, text, g_strlen(text)); SetServiceStatus(g_ssh, &g_service_status); g_listen = xrdp_listen_create(); xrdp_listen_main_loop(g_listen); g_sleep(100); g_service_status.dwCurrentState = SERVICE_STOPPED; SetServiceStatus(g_ssh, &g_service_status); } else { //g_sprintf(text, "RegisterServiceCtrlHandler failed\r\n"); //g_file_write(fd, text, g_strlen(text)); } xrdp_listen_delete(g_listen); tc_mutex_delete(g_sync_mutex); tc_mutex_delete(g_sync1_mutex); g_destroy_wait_obj(g_term_event); g_destroy_wait_obj(g_sync_event); WSACleanup(); //CloseHandle(event_han); } #endif /*****************************************************************************/ int DEFAULT_CC main(int argc, char** argv) { int test; int host_be; #if defined(_WIN32) WSADATA w; SC_HANDLE sc_man; SC_HANDLE sc_ser; int run_as_service; SERVICE_TABLE_ENTRY te[2]; #else int pid; int fd; int no_daemon; char text[256]; char pid_file[256]; #endif g_init(); ssl_init(); /* check compiled endian with actual endian */ test = 1; host_be = !((int)(*(unsigned char*)(&test))); #if defined(B_ENDIAN) if (!host_be) #endif #if defined(L_ENDIAN) if (host_be) #endif { g_writeln("endian wrong, edit arch.h"); return 0; } /* check long, int and void* sizes */ if (sizeof(int) != 4) { g_writeln("unusable int size, must be 4"); return 0; } if (sizeof(long) != sizeof(void*)) { g_writeln("long size must match void* size"); return 0; } if (sizeof(long) != 4 && sizeof(long) != 8) { g_writeln("unusable long size, must be 4 or 8"); return 0; } if (sizeof(tui64) != 8) { g_writeln("unusable tui64 size, must be 8"); return 0; } #if defined(_WIN32) run_as_service = 1; if (argc == 2) { if (g_strncasecmp(argv[1], "-help", 255) == 0 || g_strncasecmp(argv[1], "--help", 255) == 0 || g_strncasecmp(argv[1], "-h", 255) == 0) { g_writeln(""); g_writeln("xrdp: A Remote Desktop Protocol server."); g_writeln("Copyright (C) Jay Sorg 2004-2011"); g_writeln("See http://xrdp.sourceforge.net for more information."); g_writeln(""); g_writeln("Usage: xrdp [options]"); g_writeln(" -h: show help"); g_writeln(" -install: install service"); g_writeln(" -remove: remove service"); g_writeln(""); g_exit(0); } else if (g_strncasecmp(argv[1], "-install", 255) == 0 || g_strncasecmp(argv[1], "--install", 255) == 0 || g_strncasecmp(argv[1], "-i", 255) == 0) { /* open service manager */ sc_man = OpenSCManager(0, 0, GENERIC_WRITE); if (sc_man == 0) { g_writeln("error OpenSCManager, do you have rights?"); g_exit(0); } /* check if service is allready installed */ sc_ser = OpenService(sc_man, "xrdp", SERVICE_ALL_ACCESS); if (sc_ser == 0) { /* install service */ CreateService(sc_man, "xrdp", "xrdp", SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, SERVICE_DEMAND_START, SERVICE_ERROR_IGNORE, "c:\\temp\\xrdp\\xrdp.exe", 0, 0, 0, 0, 0); } else { g_writeln("error service is allready installed"); CloseServiceHandle(sc_ser); CloseServiceHandle(sc_man); g_exit(0); } CloseServiceHandle(sc_man); g_exit(0); } else if (g_strncasecmp(argv[1], "-remove", 255) == 0 || g_strncasecmp(argv[1], "--remove", 255) == 0 || g_strncasecmp(argv[1], "-r", 255) == 0) { /* open service manager */ sc_man = OpenSCManager(0, 0, GENERIC_WRITE); if (sc_man == 0) { g_writeln("error OpenSCManager, do you have rights?"); g_exit(0); } /* check if service is allready installed */ sc_ser = OpenService(sc_man, "xrdp", SERVICE_ALL_ACCESS); if (sc_ser == 0) { g_writeln("error service is not installed"); CloseServiceHandle(sc_man); g_exit(0); } DeleteService(sc_ser); CloseServiceHandle(sc_man); g_exit(0); } else { g_writeln("Unknown Parameter"); g_writeln("xrdp -h for help"); g_writeln(""); g_exit(0); } } else if (argc > 1) { g_writeln("Unknown Parameter"); g_writeln("xrdp -h for help"); g_writeln(""); g_exit(0); } if (run_as_service) { g_memset(&te, 0, sizeof(te)); te[0].lpServiceName = "xrdp"; te[0].lpServiceProc = MyServiceMain; StartServiceCtrlDispatcher(&te); g_exit(0); } WSAStartup(2, &w); #else /* _WIN32 */ g_snprintf(pid_file, 255, "%s/xrdp.pid", XRDP_PID_PATH); no_daemon = 0; if (argc == 2) { if ((g_strncasecmp(argv[1], "-kill", 255) == 0) || (g_strncasecmp(argv[1], "--kill", 255) == 0) || (g_strncasecmp(argv[1], "-k", 255) == 0)) { g_writeln("stopping xrdp"); /* read the xrdp.pid file */ fd = -1; if (g_file_exist(pid_file)) /* xrdp.pid */ { fd = g_file_open(pid_file); /* xrdp.pid */ } if (fd == -1) { g_writeln("problem opening to xrdp.pid"); g_writeln("maybe its not running"); } else { g_memset(text, 0, 32); g_file_read(fd, text, 31); pid = g_atoi(text); g_writeln("stopping process id %d", pid); if (pid > 0) { g_sigterm(pid); } g_file_close(fd); } g_exit(0); } else if (g_strncasecmp(argv[1], "-nodaemon", 255) == 0 || g_strncasecmp(argv[1], "--nodaemon", 255) == 0 || g_strncasecmp(argv[1], "-nd", 255) == 0 || g_strncasecmp(argv[1], "--nd", 255) == 0 || g_strncasecmp(argv[1], "-ns", 255) == 0 || g_strncasecmp(argv[1], "--ns", 255) == 0) { no_daemon = 1; } else if (g_strncasecmp(argv[1], "-help", 255) == 0 || g_strncasecmp(argv[1], "--help", 255) == 0 || g_strncasecmp(argv[1], "-h", 255) == 0) { g_writeln(""); g_writeln("xrdp: A Remote Desktop Protocol server."); g_writeln("Copyright (C) Jay Sorg 2004-2011"); g_writeln("See http://xrdp.sourceforge.net for more information."); g_writeln(""); g_writeln("Usage: xrdp [options]"); g_writeln(" -h: show help"); g_writeln(" -nodaemon: don't fork into background"); g_writeln(" -kill: shut down xrdp"); g_writeln(""); g_exit(0); } else if ((g_strncasecmp(argv[1], "-v", 255) == 0) || (g_strncasecmp(argv[1], "--version", 255) == 0)) { g_writeln(""); g_writeln("xrdp: A Remote Desktop Protocol server."); g_writeln("Copyright (C) Jay Sorg 2004-2011"); g_writeln("See http://xrdp.sourceforge.net for more information."); g_writeln("Version %s",PACKAGE_VERSION); g_writeln(""); g_exit(0); } else { g_writeln("Unknown Parameter"); g_writeln("xrdp -h for help"); g_writeln(""); g_exit(0); } } else if (argc > 1) { g_writeln("Unknown Parameter"); g_writeln("xrdp -h for help"); g_writeln(""); g_exit(0); } if (g_file_exist(pid_file)) /* xrdp.pid */ { g_writeln("It looks like xrdp is allready running,"); g_writeln("if not delete the xrdp.pid file and try again"); g_exit(0); } if (!no_daemon) { /* make sure we can write to pid file */ fd = g_file_open(pid_file); /* xrdp.pid */ if (fd == -1) { g_writeln("running in daemon mode with no access to pid files, quitting"); g_exit(0); } if (g_file_write(fd, "0", 1) == -1) { g_writeln("running in daemon mode with no access to pid files, quitting"); g_exit(0); } g_file_close(fd); g_file_delete(pid_file); } if (!no_daemon) { /* start of daemonizing code */ pid = g_fork(); if (pid == -1) { g_writeln("problem forking"); g_exit(1); } if (0 != pid) { g_writeln("process %d started ok", pid); /* exit, this is the main process */ g_exit(0); } g_sleep(1000); g_file_close(0); g_file_close(1); g_file_close(2); g_file_open("/dev/null"); g_file_open("/dev/null"); g_file_open("/dev/null"); /* end of daemonizing code */ } if (!no_daemon) { /* write the pid to file */ pid = g_getpid(); fd = g_file_open(pid_file); /* xrdp.pid */ if (fd == -1) { g_writeln("trying to write process id to xrdp.pid"); g_writeln("problem opening xrdp.pid"); g_writeln("maybe no rights"); } else { g_sprintf(text, "%d", pid); g_file_write(fd, text, g_strlen(text)); g_file_close(fd); } } #endif g_threadid = tc_get_threadid(); g_listen = xrdp_listen_create(); g_signal_user_interrupt(xrdp_shutdown); /* SIGINT */ g_signal_kill(xrdp_shutdown); /* SIGKILL */ g_signal_pipe(pipe_sig); /* SIGPIPE */ g_signal_terminate(xrdp_shutdown); /* SIGTERM */ g_sync_mutex = tc_mutex_create(); g_sync1_mutex = tc_mutex_create(); pid = g_getpid(); g_snprintf(text, 255, "xrdp_%8.8x_main_term", pid); g_term_event = g_create_wait_obj(text); g_snprintf(text, 255, "xrdp_%8.8x_main_sync", pid); g_sync_event = g_create_wait_obj(text); if (g_term_event == 0) { g_writeln("error creating g_term_event"); } xrdp_listen_main_loop(g_listen); xrdp_listen_delete(g_listen); tc_mutex_delete(g_sync_mutex); tc_mutex_delete(g_sync1_mutex); g_delete_wait_obj(g_term_event); g_delete_wait_obj(g_sync_event); #if defined(_WIN32) /* I don't think it ever gets here */ /* when running in win32 app mode, control c exits right away */ WSACleanup(); #else /* delete the xrdp.pid file */ g_file_delete(pid_file); #endif return 0; } xrdp-0.6.0/xup/000077500000000000000000000000001203155130500133015ustar00rootroot00000000000000xrdp-0.6.0/xup/Makefile.am000066400000000000000000000005431203155130500153370ustar00rootroot00000000000000EXTRA_DIST = xup.h AM_CFLAGS = \ -DXRDP_CFG_PATH=\"${sysconfdir}/xrdp\" \ -DXRDP_SBIN_PATH=\"${sbindir}\" \ -DXRDP_SHARE_PATH=\"${datadir}/xrdp\" \ -DXRDP_PID_PATH=\"${localstatedir}/run\" INCLUDES = \ -I$(top_srcdir)/common lib_LTLIBRARIES = \ libxup.la libxup_la_SOURCES = xup.c libxup_la_LIBADD = \ $(top_srcdir)/common/libcommon.la xrdp-0.6.0/xup/xup.c000066400000000000000000000333501203155130500142650ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2005-2010 libxup main file */ #include "xup.h" /******************************************************************************/ /* returns error */ int DEFAULT_CC lib_recv(struct mod* mod, char* data, int len) { int rcvd; if (mod->sck_closed) { return 1; } while (len > 0) { rcvd = g_tcp_recv(mod->sck, data, len, 0); if (rcvd == -1) { if (g_tcp_last_error_would_block(mod->sck)) { if (mod->server_is_term(mod)) { return 1; } g_tcp_can_recv(mod->sck, 10); } else { return 1; } } else if (rcvd == 0) { mod->sck_closed = 1; return 1; } else { data += rcvd; len -= rcvd; } } return 0; } /*****************************************************************************/ /* returns error */ int DEFAULT_CC lib_send(struct mod* mod, char* data, int len) { int sent; if (mod->sck_closed) { return 1; } while (len > 0) { sent = g_tcp_send(mod->sck, data, len, 0); if (sent == -1) { if (g_tcp_last_error_would_block(mod->sck)) { if (mod->server_is_term(mod)) { return 1; } g_tcp_can_send(mod->sck, 10); } else { return 1; } } else if (sent == 0) { mod->sck_closed = 1; return 1; } else { data += sent; len -= sent; } } return 0; } /******************************************************************************/ /* return error */ int DEFAULT_CC lib_mod_start(struct mod* mod, int w, int h, int bpp) { LIB_DEBUG(mod, "in lib_mod_start"); mod->width = w; mod->height = h; mod->bpp = bpp; LIB_DEBUG(mod, "out lib_mod_start"); return 0; } /******************************************************************************/ /* return error */ int DEFAULT_CC lib_mod_connect(struct mod* mod) { int error; int len; int i; int index; struct stream* s; char con_port[256]; LIB_DEBUG(mod, "in lib_mod_connect"); /* clear screen */ mod->server_begin_update(mod); mod->server_set_fgcolor(mod, 0); mod->server_fill_rect(mod, 0, 0, mod->width, mod->height); mod->server_end_update(mod); mod->server_msg(mod, "started connecting", 0); /* only support 8, 15, 16, and 24 bpp connections from rdp client */ if (mod->bpp != 8 && mod->bpp != 15 && mod->bpp != 16 && mod->bpp != 24) { mod->server_msg(mod, "error - only supporting 8, 15, 16, and 24 bpp rdp connections", 0); LIB_DEBUG(mod, "out lib_mod_connect error"); return 1; } if (g_strcmp(mod->ip, "") == 0) { mod->server_msg(mod, "error - no ip set", 0); LIB_DEBUG(mod, "out lib_mod_connect error"); return 1; } make_stream(s); g_sprintf(con_port, "%s", mod->port); mod->sck_closed = 0; i = 0; while (1) { mod->sck = g_tcp_socket(); g_tcp_set_non_blocking(mod->sck); g_tcp_set_no_delay(mod->sck); mod->server_msg(mod, "connecting...", 0); error = g_tcp_connect(mod->sck, mod->ip, con_port); if (error == -1) { if (g_tcp_last_error_would_block(mod->sck)) { error = 0; index = 0; while (!g_tcp_can_send(mod->sck, 100)) { index++; if ((index >= 30) || mod->server_is_term(mod)) { mod->server_msg(mod, "connect timeout", 0); error = 1; break; } } } else { mod->server_msg(mod, "connect error", 0); } } if (error == 0) { break; } g_tcp_close(mod->sck); mod->sck = 0; i++; if (i >= 4) { mod->server_msg(mod, "connection problem, giving up", 0); break; } g_sleep(250); } if (error == 0) { init_stream(s, 8192); s_push_layer(s, iso_hdr, 4); out_uint16_le(s, 103); out_uint32_le(s, 300); out_uint32_le(s, mod->width); out_uint32_le(s, mod->height); out_uint32_le(s, mod->bpp); out_uint32_le(s, 0); s_mark_end(s); len = (int)(s->end - s->data); s_pop_layer(s, iso_hdr); out_uint32_le(s, len); lib_send(mod, s->data, len); } if (error == 0) { init_stream(s, 8192); s_push_layer(s, iso_hdr, 4); out_uint16_le(s, 103); out_uint32_le(s, 200); /* x and y */ i = 0; out_uint32_le(s, i); /* width and height */ i = ((mod->width & 0xffff) << 16) | mod->height; out_uint32_le(s, i); out_uint32_le(s, 0); out_uint32_le(s, 0); s_mark_end(s); len = (int)(s->end - s->data); s_pop_layer(s, iso_hdr); out_uint32_le(s, len); lib_send(mod, s->data, len); } free_stream(s); if (error != 0) { mod->server_msg(mod, "some problem", 0); LIB_DEBUG(mod, "out lib_mod_connect error"); return 1; } else { mod->server_msg(mod, "connected ok", 0); mod->sck_obj = g_create_wait_obj_from_socket(mod->sck, 0); } LIB_DEBUG(mod, "out lib_mod_connect"); return 0; } /******************************************************************************/ /* return error */ int DEFAULT_CC lib_mod_event(struct mod* mod, int msg, tbus param1, tbus param2, tbus param3, tbus param4) { struct stream* s; int len; int key; int rv; LIB_DEBUG(mod, "in lib_mod_event"); make_stream(s); if ((msg >= 15) && (msg <= 16)) /* key events */ { key = param2; if (key > 0) { if (key == 65027) /* altgr */ { if (mod->shift_state) { g_writeln("special"); /* fix for mstsc sending left control down with altgr */ /* control down / up msg param1 param2 param3 param4 15 0 65507 29 0 16 0 65507 29 49152 */ init_stream(s, 8192); s_push_layer(s, iso_hdr, 4); out_uint16_le(s, 103); out_uint32_le(s, 16); /* key up */ out_uint32_le(s, 0); out_uint32_le(s, 65507); /* left control */ out_uint32_le(s, 29); /* RDP scan code */ out_uint32_le(s, 0xc000); /* flags */ s_mark_end(s); len = (int)(s->end - s->data); s_pop_layer(s, iso_hdr); out_uint32_le(s, len); lib_send(mod, s->data, len); } } if (key == 65507) /* left control */ { mod->shift_state = msg == 15; } } } init_stream(s, 8192); s_push_layer(s, iso_hdr, 4); out_uint16_le(s, 103); out_uint32_le(s, msg); out_uint32_le(s, param1); out_uint32_le(s, param2); out_uint32_le(s, param3); out_uint32_le(s, param4); s_mark_end(s); len = (int)(s->end - s->data); s_pop_layer(s, iso_hdr); out_uint32_le(s, len); rv = lib_send(mod, s->data, len); free_stream(s); LIB_DEBUG(mod, "out lib_mod_event"); return rv; } /******************************************************************************/ /* return error */ int DEFAULT_CC lib_mod_signal(struct mod* mod) { struct stream* s; int num_orders; int index; int rv; int len; int type; int x; int y; int cx; int cy; int fgcolor; int opcode; int width; int height; int srcx; int srcy; int len_bmpdata; int style; int x1; int y1; int x2; int y2; char* bmpdata; char cur_data[32 * (32 * 3)]; char cur_mask[32 * (32 / 8)]; LIB_DEBUG(mod, "in lib_mod_signal"); make_stream(s); init_stream(s, 8192); rv = lib_recv(mod, s->data, 8); if (rv == 0) { in_uint16_le(s, type); in_uint16_le(s, num_orders); in_uint32_le(s, len); if (type == 1) { init_stream(s, len); rv = lib_recv(mod, s->data, len); if (rv == 0) { for (index = 0; index < num_orders; index++) { in_uint16_le(s, type); switch (type) { case 1: /* server_begin_update */ rv = mod->server_begin_update(mod); break; case 2: /* server_end_update */ rv = mod->server_end_update(mod); break; case 3: /* server_fill_rect */ in_sint16_le(s, x); in_sint16_le(s, y); in_uint16_le(s, cx); in_uint16_le(s, cy); rv = mod->server_fill_rect(mod, x, y, cx, cy); break; case 4: /* server_screen_blt */ in_sint16_le(s, x); in_sint16_le(s, y); in_uint16_le(s, cx); in_uint16_le(s, cy); in_sint16_le(s, srcx); in_sint16_le(s, srcy); rv = mod->server_screen_blt(mod, x, y, cx, cy, srcx, srcy); break; case 5: /* server_paint_rect */ in_sint16_le(s, x); in_sint16_le(s, y); in_uint16_le(s, cx); in_uint16_le(s, cy); in_uint32_le(s, len_bmpdata); in_uint8p(s, bmpdata, len_bmpdata); in_uint16_le(s, width); in_uint16_le(s, height); in_sint16_le(s, srcx); in_sint16_le(s, srcy); rv = mod->server_paint_rect(mod, x, y, cx, cy, bmpdata, width, height, srcx, srcy); break; case 10: /* server_set_clip */ in_sint16_le(s, x); in_sint16_le(s, y); in_uint16_le(s, cx); in_uint16_le(s, cy); rv = mod->server_set_clip(mod, x, y, cx, cy); break; case 11: /* server_reset_clip */ rv = mod->server_reset_clip(mod); break; case 12: /* server_set_fgcolor */ in_uint32_le(s, fgcolor); rv = mod->server_set_fgcolor(mod, fgcolor); break; case 14: in_uint16_le(s, opcode); rv = mod->server_set_opcode(mod, opcode); break; case 17: in_uint16_le(s, style); in_uint16_le(s, width); rv = mod->server_set_pen(mod, style, width); break; case 18: in_sint16_le(s, x1); in_sint16_le(s, y1); in_sint16_le(s, x2); in_sint16_le(s, y2); rv = mod->server_draw_line(mod, x1, y1, x2, y2); break; case 19: in_sint16_le(s, x); in_sint16_le(s, y); in_uint8a(s, cur_data, 32 * (32 * 3)); in_uint8a(s, cur_mask, 32 * (32 / 8)); rv = mod->server_set_cursor(mod, x, y, cur_data, cur_mask); break; default: rv = 1; break; } if (rv != 0) { break; } } } } } free_stream(s); LIB_DEBUG(mod, "out lib_mod_signal"); return rv; } /******************************************************************************/ /* return error */ int DEFAULT_CC lib_mod_end(struct mod* mod) { return 0; } /******************************************************************************/ /* return error */ int DEFAULT_CC lib_mod_set_param(struct mod* mod, char* name, char* value) { if (g_strcasecmp(name, "username") == 0) { g_strncpy(mod->username, value, 255); } else if (g_strcasecmp(name, "password") == 0) { g_strncpy(mod->password, value, 255); } else if (g_strcasecmp(name, "ip") == 0) { g_strncpy(mod->ip, value, 255); } else if (g_strcasecmp(name, "port") == 0) { g_strncpy(mod->port, value, 255); } return 0; } /******************************************************************************/ /* return error */ int DEFAULT_CC lib_mod_get_wait_objs(struct mod* mod, tbus* read_objs, int* rcount, tbus* write_objs, int* wcount, int* timeout) { int i; i = *rcount; if (mod != 0) { if (mod->sck_obj != 0) { read_objs[i++] = mod->sck_obj; } } *rcount = i; return 0; } /******************************************************************************/ /* return error */ int DEFAULT_CC lib_mod_check_wait_objs(struct mod* mod) { int rv; rv = 0; if (mod != 0) { if (mod->sck_obj != 0) { if (g_is_wait_obj_set(mod->sck_obj)) { rv = lib_mod_signal(mod); } } } return rv; } /******************************************************************************/ struct mod* EXPORT_CC mod_init(void) { struct mod* mod; mod = (struct mod*)g_malloc(sizeof(struct mod), 1); mod->size = sizeof(struct mod); mod->version = CURRENT_MOD_VER; mod->handle = (tbus)mod; mod->mod_connect = lib_mod_connect; mod->mod_start = lib_mod_start; mod->mod_event = lib_mod_event; mod->mod_signal = lib_mod_signal; mod->mod_end = lib_mod_end; mod->mod_set_param = lib_mod_set_param; mod->mod_get_wait_objs = lib_mod_get_wait_objs; mod->mod_check_wait_objs = lib_mod_check_wait_objs; return mod; } /******************************************************************************/ int EXPORT_CC mod_exit(struct mod* mod) { if (mod == 0) { return 0; } g_delete_wait_obj_from_socket(mod->sck_obj); g_tcp_close(mod->sck); g_free(mod); return 0; } xrdp-0.6.0/xup/xup.h000066400000000000000000000106771203155130500143010ustar00rootroot00000000000000/* 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. xrdp: A Remote Desktop Protocol server. Copyright (C) Jay Sorg 2005-2010 libxup main header file */ /* include other h files */ #include "arch.h" #include "parse.h" #include "os_calls.h" #include "defines.h" #define CURRENT_MOD_VER 2 struct mod { int size; /* size of this struct */ int version; /* internal version */ /* client functions */ int (*mod_start)(struct mod* v, int w, int h, int bpp); int (*mod_connect)(struct mod* v); int (*mod_event)(struct mod* v, int msg, tbus param1, tbus param2, tbus param3, tbus param4); int (*mod_signal)(struct mod* v); int (*mod_end)(struct mod* v); int (*mod_set_param)(struct mod* v, char* name, char* value); int (*mod_session_change)(struct mod* v, int, int); int (*mod_get_wait_objs)(struct mod* v, tbus* read_objs, int* rcount, tbus* write_objs, int* wcount, int* timeout); int (*mod_check_wait_objs)(struct mod* v); tbus mod_dumby[100 - 9]; /* align, 100 minus the number of mod functions above */ /* server functions */ int (*server_begin_update)(struct mod* v); int (*server_end_update)(struct mod* v); int (*server_fill_rect)(struct mod* v, int x, int y, int cx, int cy); int (*server_screen_blt)(struct mod* v, int x, int y, int cx, int cy, int srcx, int srcy); int (*server_paint_rect)(struct mod* v, int x, int y, int cx, int cy, char* data, int width, int height, int srcx, int srcy); int (*server_set_cursor)(struct mod* v, int x, int y, char* data, char* mask); int (*server_palette)(struct mod* v, int* palette); int (*server_msg)(struct mod* v, char* msg, int code); int (*server_is_term)(struct mod* v); int (*server_set_clip)(struct mod* v, int x, int y, int cx, int cy); int (*server_reset_clip)(struct mod* v); int (*server_set_fgcolor)(struct mod* v, int fgcolor); int (*server_set_bgcolor)(struct mod* v, int bgcolor); int (*server_set_opcode)(struct mod* v, int opcode); int (*server_set_mixmode)(struct mod* v, int mixmode); int (*server_set_brush)(struct mod* v, int x_orgin, int y_orgin, int style, char* pattern); int (*server_set_pen)(struct mod* v, int style, int width); int (*server_draw_line)(struct mod* v, int x1, int y1, int x2, int y2); int (*server_add_char)(struct mod* v, int font, int charactor, int offset, int baseline, int width, int height, char* data); int (*server_draw_text)(struct mod* v, int font, int flags, int mixmode, int clip_left, int clip_top, int clip_right, int clip_bottom, int box_left, int box_top, int box_right, int box_bottom, int x, int y, char* data, int data_len); int (*server_reset)(struct mod* v, int width, int height, int bpp); int (*server_query_channel)(struct mod* v, int index, char* channel_name, int* channel_flags); int (*server_get_channel_id)(struct mod* v, char* name); int (*server_send_to_channel)(struct mod* v, int channel_id, char* data, int data_len, int total_data_len, int flags); int (*server_bell_trigger)(struct mod* v); tbus server_dumby[100 - 25]; /* align, 100 minus the number of server functions above */ /* common */ tbus handle; /* pointer to self as long */ tbus wm; tbus painter; int sck; /* mod data */ int width; int height; int bpp; int sck_closed; char username[256]; char password[256]; char ip[256]; char port[256]; tbus sck_obj; int shift_state; };