Removed some debugging stuff, correct RDP5 bitmap sending.
[rdpsrv] / rdp.c
1 /* -*- c-basic-offset: 8 -*-
2    rdesktop: A Remote Desktop Protocol client.
3    Protocol services - RDP layer
4    Copyright (C) Matthew Chapman 1999-2002
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 #include <time.h>
22 #include "rdesktop.h"
23
24 extern uint16 g_mcs_userid;
25 extern char g_username[16];
26 extern BOOL g_bitmap_compression;
27 extern BOOL g_orders;
28 BOOL g_encryption = 0;
29 extern BOOL g_desktop_save;
30 extern BOOL g_use_rdp5;
31 extern uint16 g_server_rdp_version;
32 extern int g_server_bpp;
33
34 uint8 *g_next_packet;
35 uint32 g_rdp_shareid;
36
37 #if WITH_DEBUG
38 static uint32 g_packetno;
39 #endif
40
41 /* Receive an RDP packet */
42 STREAM
43 rdp_recv(uint8 * type)
44 {
45         static STREAM rdp_s;
46         uint16 length, pdu_type;
47
48         if ((rdp_s == NULL) || (g_next_packet >= rdp_s->end))
49         {
50                 rdp_s = sec_recv();
51                 if (rdp_s == NULL)
52                         return NULL;
53
54                 g_next_packet = rdp_s->p;
55         }
56         else
57         {
58                 rdp_s->p = g_next_packet;
59         }
60
61         in_uint16_le(rdp_s, length);
62         /* 32k packets are really 8, keepalive fix */
63         if (length == 0x8000)
64         {
65                 g_next_packet += 8;
66                 *type = 0;
67                 return rdp_s;
68         }
69         in_uint16_le(rdp_s, pdu_type);
70         in_uint8s(rdp_s, 2);    /* userid */
71         *type = pdu_type & 0xf;
72
73 #if WITH_DEBUG
74         DEBUG(("RDP packet #%d, (type %x, length %u)\n", ++g_packetno, *type, length));
75         //hexdump(g_next_packet, length);
76 #endif /*  */
77
78         g_next_packet += length;
79         return rdp_s;
80 }
81
82 /* Initialise an RDP data packet */
83 STREAM
84 rdp_init_data(int maxlen)
85 {
86         STREAM s;
87
88         s = sec_init(g_encryption ? SEC_ENCRYPT : 0, maxlen + 18);
89         s_push_layer(s, rdp_hdr, 18);
90
91         return s;
92 }
93
94 /* Send an RDP data packet */
95 void
96 rdp_send_data(STREAM s, uint8 data_pdu_type)
97 {
98         uint16 length;
99
100         s_pop_layer(s, rdp_hdr);
101         length = s->end - s->p;
102
103         out_uint16_le(s, length);
104         out_uint16_le(s, (RDP_PDU_DATA | 0x10));
105         out_uint16_le(s, (g_mcs_userid + 1001));
106
107         out_uint32_le(s, g_rdp_shareid);
108         out_uint8(s, 0);        /* pad */
109         out_uint8(s, 1);        /* streamid */
110         out_uint16_le(s, (length - 14));
111         out_uint8(s, data_pdu_type);
112         out_uint8(s, 0);        /* compress_type */
113         out_uint16(s, 0);       /* compress_len */
114
115         sec_send(s, g_encryption ? SEC_ENCRYPT : 0);
116 }
117
118 /* Output a string in Unicode */
119 void
120 rdp_out_unistr(STREAM s, char *string, int len)
121 {
122         int i = 0, j = 0;
123
124         len += 2;
125
126         while (i < len)
127         {
128                 s->p[i++] = string[j++];
129                 s->p[i++] = 0;
130         }
131
132         s->p += len;
133 }
134
135 /* Input a string in Unicode (uuuuuuugly, use iconv later) */
136 void
137 rdp_in_unistr(STREAM s, char *string, int len)
138 {
139         int i = 0, j = 0;
140         len += 2;
141
142         while (i < len)
143         {
144                 string[j++] = s->p[i];
145                 i += 2;
146         }
147         
148         s->p += len;
149 }
150
151 void rdp_send_bitmap_update(unsigned x, unsigned y, unsigned width, unsigned height, unsigned char *data)
152 {
153         STREAM s;
154
155         int length = 10*2 + width*height*3 + 8;
156
157         printf("RDP5 chunk length: %u\n", 10*2 + width*height*3 + 2);
158         
159         s = tcp_init(length);
160         out_uint8(s, 0); // version (RDP5)
161         out_uint8(s, 0x80 | (length >> 8));
162         out_uint8(s, length & 0xff);
163
164         out_uint8(s, 1); // process bitmap update
165         out_uint16_le(s, 10*2 + width*height*3 + 2); // RDP5 chunk length
166         out_uint16_le(s, 10*2 + width*height*3);     // part length
167
168         out_uint16_le(s, 1); // one update
169         out_uint16_le(s, x); // left, top, right, bottom
170         out_uint16_le(s, y);
171         out_uint16_le(s, x+width);
172         out_uint16_le(s, y+height);
173         out_uint16_le(s, width); // width, height
174         out_uint16_le(s, height);
175         out_uint16_le(s, 24); // bpp
176         out_uint16_le(s, 0); // no compression
177         out_uint16_le(s, width*height*3); // bufsize
178
179         out_uint8p(s, data, width*height*3);
180         
181         s_mark_end(s);
182         tcp_send(s);
183 }
184
185 #define EXPECT16(value) { in_uint16_le(s, unknown); if (unknown != (value)) printf("Unknown value on code line %u; expected 0x%x, got 0x%x\n", __LINE__, (value), unknown); }
186 #define EXPECT32(value) { in_uint32_le(s, unknown); if (unknown != (value)) printf("Unknown value on code line %u; expected 0x%x, got 0x%x\n", __LINE__, (value), unknown); }
187
188 void
189 rdp_get_logon_info(STREAM s)
190 {
191         uint32 flags, unknown;
192         uint16 tzone_major, tzone_minor;
193         int len_domain, len_user, len_password, len_program, len_directory, len_ip, len_dll;
194         char domain[256], user[256], password[256], program[256], directory[256], ip[256], dll[256], tz1[256], tz2[256]; // FIXME
195         
196         in_uint32_le(s, unknown);
197         in_uint32_le(s, flags);
198         
199         printf("logon flags: %x\n", flags);
200
201         if (flags & RDP_LOGON_BLOB) { 
202                 printf("RDP5-style logon packet\n");
203
204                 in_uint16_le(s, len_domain);
205                 in_uint16_le(s, len_user);
206
207                 if (flags & RDP_LOGON_AUTO) {
208                         in_uint16_le(s, len_password);
209                 } else {
210                         strcpy(password, "<none>");
211                 }
212                 if (flags & RDP_LOGON_BLOB && !(flags & RDP_LOGON_AUTO)) {
213                         // is this too some kind of length?
214                         EXPECT16(0);
215                 }
216                 in_uint16_le(s, len_program);
217                 in_uint16_le(s, len_directory);
218                 
219                 rdp_in_unistr(s, domain, len_domain);
220                 rdp_in_unistr(s, user, len_user);
221
222                 if (flags & RDP_LOGON_AUTO)
223                         rdp_in_unistr(s, password, len_password);
224                 
225                 if (flags & RDP_LOGON_BLOB && !(flags & RDP_LOGON_AUTO))
226                         EXPECT16(0);
227                         
228                 rdp_in_unistr(s, program, len_program);
229                 rdp_in_unistr(s, directory, len_directory);
230
231                 EXPECT16(2);
232
233                 in_uint16_le(s, len_ip);
234                 rdp_in_unistr(s, ip, len_ip - 2);
235
236                 in_uint16_le(s, len_dll);
237                 rdp_in_unistr(s, dll, len_dll - 2);
238
239                 in_uint16_le(s, tzone_major);
240                 in_uint16_le(s, tzone_minor);
241
242                 // time zone names?
243                 rdp_in_unistr(s, tz1, 62);
244                 EXPECT32(0x0a0000);
245                 EXPECT32(0x050000);
246                 EXPECT32(3);
247                 EXPECT32(0);
248                 EXPECT32(0);
249
250                 rdp_in_unistr(s, tz2, 62);
251                 EXPECT32(0x030000);
252                 EXPECT32(0x050000);
253                 EXPECT32(2);
254                 EXPECT32(0);
255                 EXPECT32(0xffffffc4);
256                 EXPECT32(0xfffffffe);
257                 EXPECT32(0x0f);
258                 EXPECT32(0);
259
260                 printf("domain='%s'\n", domain);
261                 printf("user='%s'\n", user);
262                 printf("password='%s'\n", password);
263                 printf("program='%s'\n", program);
264                 printf("directory='%s'\n", directory);
265                 printf("ip='%s'\n", ip);
266                 printf("dll='%s'\n", dll);
267                 printf("timezone=%d:%02d\n", tzone_major, tzone_minor);
268                 printf("tz1='%64s'\n", tz1);
269                 printf("tz2='%64s'\n", tz2);
270         } else {
271                 in_uint16_le(s, len_domain);
272                 in_uint16_le(s, len_user);
273                 in_uint16_le(s, len_password);
274                 in_uint16_le(s, len_program);
275                 in_uint16_le(s, len_directory);
276                 rdp_in_unistr(s, domain, len_domain);
277                 rdp_in_unistr(s, user, len_user);
278                 rdp_in_unistr(s, password, len_password);
279                 rdp_in_unistr(s, program, len_program);
280                 rdp_in_unistr(s, directory, len_directory);
281
282                 printf("domain='%s'\n", domain);
283                 printf("user='%s'\n", user);
284                 printf("password='%s'\n", password);
285                 printf("program='%s'\n", program);
286                 printf("directory='%s'\n", directory);
287         }
288
289         if (!s_check_end(s)) {
290                 printf("Unknown data at end of logon packet!\n");
291         }
292 }
293
294 /* Send a control PDU */
295 static void
296 rdp_send_control(uint16 action)
297 {
298         STREAM s;
299
300         s = rdp_init_data(8);
301
302         out_uint16_le(s, action);
303         out_uint16(s, 0);       /* userid */
304         out_uint32(s, 0);       /* control id */
305
306         s_mark_end(s);
307         rdp_send_data(s, RDP_DATA_PDU_CONTROL);
308 }
309
310 /* Send a synchronisation PDU */
311 static void
312 rdp_send_synchronise(void)
313 {
314         STREAM s;
315
316         s = rdp_init_data(4);
317
318         out_uint16_le(s, 1);    /* type */
319         out_uint16_le(s, 1002);
320
321         s_mark_end(s);
322         rdp_send_data(s, RDP_DATA_PDU_SYNCHRONISE);
323 }
324
325 /* Receive a single input event */
326 void
327 rdp_recv_input(STREAM s, uint32 *time, uint16 *message_type, uint16 *device_flags, uint16 *param1, uint16 *param2)
328 {
329         in_uint32_le(s, *time);
330         in_uint16_le(s, *message_type);
331         in_uint16_le(s, *device_flags);
332         in_uint16_le(s, *param1);
333         in_uint16_le(s, *param2);
334 }
335
336 /* Disconnect from the RDP layer */
337 void
338 rdp_disconnect(void)
339 {
340         sec_disconnect();
341 }