]> git.sesse.net Git - rdpsrv/blob - mcs.c
10469d860b39a7c7b5c9ad06650e4613d211b279
[rdpsrv] / mcs.c
1 /* -*- c-basic-offset: 8 -*-
2    rdesktop: A Remote Desktop Protocol client.
3    Protocol services - Multipoint Communications Service
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 "rdesktop.h"
22
23 uint16 g_mcs_userid;
24 extern VCHANNEL g_channels[];
25 extern unsigned int g_num_channels;
26
27 /* Parse an ASN.1 BER header */
28 static BOOL
29 ber_parse_header(STREAM s, int tagval, int *length)
30 {
31         int tag, len;
32
33         if (tagval > 0xff)
34         {
35                 in_uint16_be(s, tag);
36         }
37         else
38         {
39         in_uint8(s, tag)}
40
41         if (tag != tagval)
42         {
43                 error("expected tag %d, got %d\n", tagval, tag);
44                 return False;
45         }
46
47         in_uint8(s, len);
48
49         if (len & 0x80)
50         {
51                 len &= ~0x80;
52                 *length = 0;
53                 while (len--)
54                         next_be(s, *length);
55         }
56         else
57                 *length = len;
58
59         return s_check(s);
60 }
61
62 /* Output an ASN.1 BER header */
63 static void
64 ber_out_header(STREAM s, int tagval, int length)
65 {
66         if (tagval > 0xff)
67         {
68                 out_uint16_be(s, tagval);
69         }
70         else
71         {
72                 out_uint8(s, tagval);
73         }
74
75         if (length >= 0x80)
76         {
77                 out_uint8(s, 0x82);
78                 out_uint16_be(s, length);
79         }
80         else
81                 out_uint8(s, length);
82 }
83
84 /* Output an ASN.1 BER integer */
85 static void
86 ber_out_integer(STREAM s, int value)
87 {
88         ber_out_header(s, BER_TAG_INTEGER, 2);
89         out_uint16_be(s, value);
90 }
91
92 static void
93 ber_out_uint8(STREAM s, uint8 value)
94 {
95         ber_out_header(s, BER_TAG_INTEGER, 1);
96         out_uint8(s, value);
97 }
98
99 static void
100 ber_in_integer(STREAM s, int *value)
101 {
102         int length;
103         ber_parse_header(s, BER_TAG_INTEGER, &length);
104         in_uint16_be(s, *value);
105 }
106
107 /* Output a DOMAIN_PARAMS structure (ASN.1 BER) */
108 static void
109 mcs_out_domain_params(STREAM s, int max_channels, int max_users, int max_tokens, int max_pdusize)
110 {
111         ber_out_header(s, MCS_TAG_DOMAIN_PARAMS, 26);
112         ber_out_uint8(s, 34); // max_channels
113         ber_out_uint8(s, 3);  // max_users
114         ber_out_uint8(s, 0);  // max_tokens
115         ber_out_uint8(s, 1);  // num_priorities 
116         ber_out_uint8(s, 0);  // min_throughput
117         ber_out_uint8(s, 1);  // max_height
118         ber_out_header(s, BER_TAG_INTEGER, 3); // pdu size
119         out_uint8(s, 0x00);
120         out_uint8(s, 0xff);
121         out_uint8(s, 0xf8);
122         ber_out_uint8(s, 2);  // ver_protocol
123 }
124
125 /* Parse a DOMAIN_PARAMS structure (ASN.1 BER) */
126 static BOOL
127 mcs_parse_domain_params(STREAM s)
128 {
129         int length;
130         int max_channels, max_users, max_tokens, max_pdusize;
131         int num_priorities, min_throughput, max_height;
132         int ver_protocol;
133
134         ber_parse_header(s, MCS_TAG_DOMAIN_PARAMS, &length);
135         printf("MCS_TAG_DOMAIN_PARAMS, len %u (expected 32)\n", length);
136         if (length == 32) {
137                 ber_in_integer(s, &max_channels);
138                 ber_in_integer(s, &max_users);
139                 ber_in_integer(s, &max_tokens);
140                 ber_in_integer(s, &num_priorities);
141                 ber_in_integer(s, &min_throughput);
142                 ber_in_integer(s, &max_height);
143                 ber_in_integer(s, &max_pdusize);
144                 ber_in_integer(s, &ver_protocol);
145
146                 printf("max_channels=%u\n", max_channels);
147                 printf("max_users=%u\n", max_users);
148                 printf("max_tokens=%u\n", max_tokens);
149                 printf("num_priorities=%u\n", num_priorities);
150                 printf("min_throughput=%u\n", min_throughput);
151                 printf("max_pdusize=%u\n", max_pdusize);
152                 printf("ver_protocol=%u\n", ver_protocol);
153         } else {
154                 hexdump(s->p, length);
155                 in_uint8s(s, length);
156         }
157         
158         return s_check(s);
159 }
160
161 /* Expect a MCS_CONNECT_RESPONSE message (ASN.1 BER) */
162 BOOL
163 mcs_recv_connect_initial()
164 {
165         uint8 result;
166         int length;
167         STREAM s;
168         char *buf;
169
170         s = iso_recv();
171         if (s == NULL)
172                 return False;
173
174         ber_parse_header(s, MCS_CONNECT_INITIAL, &length);
175         printf("parsing MCS_CONNECT_INITIAL (len=%u)\n", length);
176         ber_parse_header(s, BER_TAG_OCTET_STRING, &length);   /* calling domain */
177         in_uint8(s, result);
178         ber_parse_header(s, BER_TAG_OCTET_STRING, &length);   /* called domain */
179         in_uint8(s, result);
180         
181         ber_parse_header(s, BER_TAG_BOOLEAN, &length);
182         in_uint8(s, result);
183
184         mcs_parse_domain_params(s);
185         mcs_parse_domain_params(s);
186         mcs_parse_domain_params(s);
187
188         ber_parse_header(s, BER_TAG_OCTET_STRING, &length);
189         in_uint8p(s, buf, length);
190
191         printf("Data from MCS connect: '%*s'\n", length, buf);
192         
193         return s_check_end(s);
194 }
195
196 /* key generated with "openssl genrsa 512 | openssl rsa -text":
197  
198 modulus:
199     00:b1:e0:36:2f:fd:dd:8b:d6:64:e9:2b:14:f8:b9:
200     0b:ba:3b:b7:0a:f1:f3:97:56:93:38:01:2f:d1:31:
201     2d:70:59:de:97:6a:61:3f:cb:a4:b4:12:05:89:14:
202     d9:b0:8a:70:03:b6:f1:ad:c5:b9:19:9b:b9:8f:03:
203     51:bf:fe:f8:e5
204 publicExponent: 65537 (0x10001)
205 privateExponent:
206     00:a4:86:68:58:97:8d:f6:2c:06:06:8d:ac:c6:2a:
207     12:a8:dd:56:ff:2e:b0:4b:08:ee:fe:dc:4a:28:4a:
208     3e:67:2d:8e:08:6b:5f:87:69:a4:c5:a0:e7:50:1a:
209     f0:71:03:46:f2:52:7c:e6:09:40:40:61:51:76:32:
210     f8:28:72:99:41
211 prime1:
212     00:db:46:d9:34:10:ce:0d:f6:f7:48:30:0f:2b:f6:
213     4d:66:40:27:00:97:db:48:77:cd:96:b5:a6:51:81:
214     a1:7c:ad
215 prime2:
216     00:cf:aa:5c:d3:8a:0d:d4:91:a6:40:92:ff:2c:31:
217     d6:f9:08:8d:e8:d2:a8:2f:89:a6:88:2c:61:68:8e:
218     ee:7c:19
219 */
220 unsigned char my_modulus[SEC_MODULUS_SIZE] = {
221         0xe5, 0xf8, 0xfe, 0xbf, 0x51,
222         0x03, 0x8f, 0xb9, 0x9b, 0x19, 0xb9, 0xc5, 0xad, 0xf1, 0xb6, 0x03, 0x70, 0x8a, 0xb0, 0xd9,
223         0x14, 0x89, 0x05, 0x12, 0xb4, 0xa4, 0xcb, 0x3f, 0x61, 0x6a, 0x97, 0xde, 0x59, 0x70, 0x2d,
224         0x31, 0xd1, 0x2f, 0x01, 0x38, 0x93, 0x56, 0x97, 0xf3, 0xf1, 0x0a, 0xb7, 0x3b, 0xba, 0x0b,
225         0xb9, 0xf8, 0x14, 0x2b, 0xe9, 0x64, 0xd6, 0x8b, 0xdd, 0xfd, 0x2f, 0x36, 0xe0, 0xb1
226 };
227 unsigned char my_exponent[SEC_EXPONENT_SIZE] = {
228         0x01, 0x00, 0x01, 0x00
229 };
230 unsigned char my_private_exponent[] = {
231         0x41, 0x99, 0x72, 0x28, 0xf8,
232         0x32, 0x76, 0x51, 0x61, 0x40, 0x40, 0x09, 0xe6, 0x7c, 0x52, 0xf2, 0x46, 0x03, 0x71, 0xf0,
233         0x1a, 0x50, 0xe7, 0xa0, 0xc5, 0xa4, 0x69, 0x87, 0x5f, 0x6b, 0x08, 0x8e, 0x2d, 0x67, 0x3e,
234         0x4a, 0x28, 0x4a, 0xdc, 0xfe, 0xee, 0x08, 0x4b, 0xb0, 0x2e, 0xff, 0x56, 0xdd, 0xa8, 0x12,
235         0x2a, 0xc6, 0xac, 0x8d, 0x06, 0x06, 0x2c, 0xf6, 0x8d, 0x97, 0x58, 0x68, 0x86, 0xa4
236 };
237
238  
239 void
240 mcs_send_connect_response()
241 {
242         STREAM s;
243         int i, length;
244
245         s = iso_init(250);
246         printf("INITLEN: %u\n", s->p - s->iso_hdr);
247
248         ber_out_header(s, MCS_CONNECT_RESPONSE, 245);
249         ber_out_header(s, BER_TAG_RESULT, 1);
250         out_uint8(s, 0);
251
252         ber_out_header(s, BER_TAG_INTEGER, 1);
253         out_uint8(s, 0);  // connect id
254         
255         mcs_out_domain_params(s, 34, 2, 0, 0xffff);  // dumdidum?
256
257         ber_out_header(s, BER_TAG_OCTET_STRING, 207);
258
259         // some unknown header of sorts
260         out_uint8(s, 0x00);
261         out_uint8(s, 0x05);
262         out_uint8(s, 0x00);
263         out_uint8(s, 0x14);
264         out_uint8(s, 0x7c);
265         out_uint8(s, 0x00);
266         out_uint8(s, 0x01);
267         out_uint8(s, 0x2a);
268         out_uint8(s, 0x14);
269         out_uint8(s, 0x76);
270         out_uint8(s, 0x0a); 
271         out_uint8(s, 0x01);
272         out_uint8(s, 0x01);
273         out_uint8(s, 0x00);
274         out_uint8(s, 0x01);
275         out_uint8(s, 0xc0);
276         out_uint8(s, 0x00);
277         out_uint8(s, 0x4d);
278         out_uint8(s, 0x63);
279         out_uint8(s, 0x44);
280         out_uint8(s, 0x6e);
281
282         length = 184;
283         
284         // two bytes of length
285         out_uint8(s, 0x80 | (length >> 7));
286         out_uint8(s, length & 0x7f);
287
288         // server info -- we claim to support RDP5
289         out_uint16_le(s, SEC_TAG_SRV_INFO);
290         out_uint16_le(s, 8);  // length
291         out_uint16_le(s, 4);  // version
292         out_uint16_le(s, 8);  // unknown
293
294         // channel info -- open a few channels
295         out_uint16_le(s, SEC_TAG_SRV_CHANNELS);
296         out_uint16_le(s, 16); // length
297         out_uint16_le(s, 1003);
298         out_uint16_le(s, 3);
299         out_uint16_le(s, 1004);
300         out_uint16_le(s, 1005);
301         out_uint16_le(s, 1006);
302         out_uint16_le(s, 0);
303         
304         // crypto info
305         out_uint16_le(s, SEC_TAG_SRV_CRYPT);
306         out_uint16_le(s, 160); // length
307         out_uint32_le(s, 1); // 40-bit
308         out_uint32_le(s, 1); // low
309
310         out_uint32_le(s, SEC_RANDOM_SIZE); // random_len
311         out_uint32_le(s, 96);             // rsa_info_len
312         out_uint8s(s, SEC_RANDOM_SIZE);    // server_random
313         out_uint32_le(s, 1);               // RDP4-style
314         out_uint8s(s, 8);                  // unknown
315
316         out_uint16_le(s, SEC_TAG_PUBKEY);
317         out_uint16_le(s, 88);
318         out_uint32_le(s, SEC_RSA_MAGIC);
319         out_uint32_le(s, SEC_MODULUS_SIZE + SEC_PADDING_SIZE);  // modulus_len
320         out_uint32_le(s, SEC_MODULUS_SIZE * 8);                 // modulus_bits
321         out_uint8s(s, 4);                                       // unknown
322         out_uint8p(s, my_exponent, SEC_EXPONENT_SIZE);
323         out_uint8p(s, my_modulus, SEC_MODULUS_SIZE);
324         out_uint8s(s, SEC_PADDING_SIZE);
325         
326         s_mark_end(s);
327         iso_send(s);
328
329 }
330
331 /* Send an EDrq message (ASN.1 PER) */
332 static void
333 mcs_send_edrq(void)
334 {
335         STREAM s;
336
337         s = iso_init(5);
338
339         out_uint8(s, (MCS_EDRQ << 2));
340         out_uint16_be(s, 1);    /* height */
341         out_uint16_be(s, 1);    /* interval */
342
343         s_mark_end(s);
344         iso_send(s);
345 }
346
347 /* Send an AUrq message (ASN.1 PER) */
348 static void
349 mcs_send_aurq(void)
350 {
351         STREAM s;
352
353         s = iso_init(1);
354
355         out_uint8(s, (MCS_AURQ << 2));
356
357         s_mark_end(s);
358         iso_send(s);
359 }
360
361 /* Send a AUcf message (ASN.1 PER) */
362 static void
363 mcs_send_aucf(uint16 mcs_userid)
364 {
365         STREAM s;
366
367         s = iso_init(4);
368
369         out_uint8(s, (MCS_AUCF << 2) | 2);  // | 2 = send user ID
370         out_uint8(s, 0);  // success
371         out_uint16_be(s, 6);
372         
373         s_mark_end(s);
374         iso_send(s);
375 }
376
377 /* Send a CJrq message (ASN.1 PER) */
378 static void
379 mcs_send_cjrq(uint16 chanid)
380 {
381         STREAM s;
382
383         DEBUG_RDP5(("Sending CJRQ for channel #%d\n", chanid));
384
385         s = iso_init(5);
386
387         out_uint8(s, (MCS_CJRQ << 2));
388         out_uint16_be(s, g_mcs_userid);
389         out_uint16_be(s, chanid);
390
391         s_mark_end(s);
392         iso_send(s);
393 }
394
395 /* Expect a CJcf message (ASN.1 PER) */
396 static void
397 mcs_send_cjcf(uint16 userid, uint16 chanid)
398 {
399         STREAM s;
400
401         s = iso_init(8);
402
403         out_uint8(s, (MCS_CJCF << 2) | 2);
404         out_uint8(s, 0); // success
405         out_uint16_be(s, 6);
406         out_uint16_be(s, chanid);
407         out_uint16_be(s, chanid);
408
409         s_mark_end(s);
410         iso_send(s);
411 }
412
413 /* Initialise an MCS transport data packet */
414 STREAM
415 mcs_init(int length)
416 {
417         STREAM s;
418
419         s = iso_init(length + 8);
420         s_push_layer(s, mcs_hdr, 8);
421
422         return s;
423 }
424
425 /* Send an MCS transport data packet to a specific channel */
426 void
427 mcs_send_to_channel(STREAM s, uint16 channel)
428 {
429         uint16 length;
430
431         s_pop_layer(s, mcs_hdr);
432         length = s->end - s->p - 8;
433         length |= 0x8000;
434
435         out_uint8(s, (MCS_SDIN << 2));
436         out_uint16_be(s, g_mcs_userid);
437         out_uint16_be(s, channel);
438         out_uint8(s, 0x70);     /* flags */
439         out_uint16_be(s, length);
440
441         iso_send(s);
442 }
443
444 /* Send an MCS transport data packet to the global channel */
445 void
446 mcs_send(STREAM s)
447 {
448         mcs_send_to_channel(s, MCS_GLOBAL_CHANNEL);
449 }
450
451 /* Receive an MCS transport data packet */
452 STREAM
453 mcs_recv(uint16 * channel)
454 {
455         uint8 opcode, appid, length, userid;
456         STREAM s;
457
458         s = iso_recv();
459         if (s == NULL)
460                 return NULL;
461
462         in_uint8(s, opcode);
463         appid = opcode >> 2;
464
465         switch (appid) {
466         case MCS_SDRQ:
467                 in_uint8s(s, 2);        /* userid */
468                 in_uint16_be(s, *channel);
469                 in_uint8s(s, 1);        /* flags */
470                 in_uint8(s, length);
471                 if (length & 0x80)
472                         in_uint8s(s, 1);        /* second byte of length */
473
474                 return s;
475         case MCS_DPUM:
476                 printf("Received DPUM (?)\n");
477                 return NULL;
478         case MCS_EDRQ:
479                 // Erect Domain (ignore)
480                 printf("Received EDrq\n");
481                 return NULL;
482         case MCS_AURQ:
483                 // Attach User Request, respond with AUcf (Attach User Confirm)
484                 printf("Received AUrq, sending AUcf\n");
485                 mcs_send_aucf(0);
486                 return NULL;
487         case MCS_CJRQ:
488                 // Channel Join Request, respond with CJcf (Channel Join Confirm);
489                 in_uint16_be(s, userid);
490                 in_uint16_be(s, *channel);
491                 printf("Received CJrq for channel %hu, sending CJcf\n", *channel);
492                 mcs_send_cjcf(userid, *channel);
493                 return NULL;
494         default:
495                 error("expected data, got %d\n", opcode);
496                 return NULL;
497         }
498
499 }
500
501 /* Disconnect from the MCS layer */
502 void
503 mcs_disconnect(void)
504 {
505         iso_disconnect();
506 }