~ubuntu-branches/ubuntu/edgy/rdesktop/edgy-security

« back to all changes in this revision

Viewing changes to mcs.c

  • Committer: Bazaar Package Importer
  • Author(s): Sam Johnston
  • Date: 2004-02-04 17:52:26 UTC
  • Revision ID: james.westby@ubuntu.com-20040204175226-87kz4bzs1nimji68
Tags: upstream-1.3.1
ImportĀ upstreamĀ versionĀ 1.3.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
/* Output a DOMAIN_PARAMS structure (ASN.1 BER) */
 
93
static void
 
94
mcs_out_domain_params(STREAM s, int max_channels, int max_users, int max_tokens, int max_pdusize)
 
95
{
 
96
        ber_out_header(s, MCS_TAG_DOMAIN_PARAMS, 32);
 
97
        ber_out_integer(s, max_channels);
 
98
        ber_out_integer(s, max_users);
 
99
        ber_out_integer(s, max_tokens);
 
100
        ber_out_integer(s, 1);  /* num_priorities */
 
101
        ber_out_integer(s, 0);  /* min_throughput */
 
102
        ber_out_integer(s, 1);  /* max_height */
 
103
        ber_out_integer(s, max_pdusize);
 
104
        ber_out_integer(s, 2);  /* ver_protocol */
 
105
}
 
106
 
 
107
/* Parse a DOMAIN_PARAMS structure (ASN.1 BER) */
 
108
static BOOL
 
109
mcs_parse_domain_params(STREAM s)
 
110
{
 
111
        int length;
 
112
 
 
113
        ber_parse_header(s, MCS_TAG_DOMAIN_PARAMS, &length);
 
114
        in_uint8s(s, length);
 
115
 
 
116
        return s_check(s);
 
117
}
 
118
 
 
119
/* Send an MCS_CONNECT_INITIAL message (ASN.1 BER) */
 
120
static void
 
121
mcs_send_connect_initial(STREAM mcs_data)
 
122
{
 
123
        int datalen = mcs_data->end - mcs_data->data;
 
124
        int length = 9 + 3 * 34 + 4 + datalen;
 
125
        STREAM s;
 
126
 
 
127
        s = iso_init(length + 5);
 
128
 
 
129
        ber_out_header(s, MCS_CONNECT_INITIAL, length);
 
130
        ber_out_header(s, BER_TAG_OCTET_STRING, 1);     /* calling domain */
 
131
        out_uint8(s, 1);
 
132
        ber_out_header(s, BER_TAG_OCTET_STRING, 1);     /* called domain */
 
133
        out_uint8(s, 1);
 
134
 
 
135
        ber_out_header(s, BER_TAG_BOOLEAN, 1);
 
136
        out_uint8(s, 0xff);     /* upward flag */
 
137
 
 
138
        mcs_out_domain_params(s, 34, 2, 0, 0xffff);     /* target params */
 
139
        mcs_out_domain_params(s, 1, 1, 1, 0x420);       /* min params */
 
140
        mcs_out_domain_params(s, 0xffff, 0xfc17, 0xffff, 0xffff);       /* max params */
 
141
 
 
142
        ber_out_header(s, BER_TAG_OCTET_STRING, datalen);
 
143
        out_uint8p(s, mcs_data->data, datalen);
 
144
 
 
145
        s_mark_end(s);
 
146
        iso_send(s);
 
147
}
 
148
 
 
149
/* Expect a MCS_CONNECT_RESPONSE message (ASN.1 BER) */
 
150
static BOOL
 
151
mcs_recv_connect_response(STREAM mcs_data)
 
152
{
 
153
        uint8 result;
 
154
        int length;
 
155
        STREAM s;
 
156
 
 
157
        s = iso_recv();
 
158
        if (s == NULL)
 
159
                return False;
 
160
 
 
161
        ber_parse_header(s, MCS_CONNECT_RESPONSE, &length);
 
162
 
 
163
        ber_parse_header(s, BER_TAG_RESULT, &length);
 
164
        in_uint8(s, result);
 
165
        if (result != 0)
 
166
        {
 
167
                error("MCS connect: %d\n", result);
 
168
                return False;
 
169
        }
 
170
 
 
171
        ber_parse_header(s, BER_TAG_INTEGER, &length);
 
172
        in_uint8s(s, length);   /* connect id */
 
173
        mcs_parse_domain_params(s);
 
174
 
 
175
        ber_parse_header(s, BER_TAG_OCTET_STRING, &length);
 
176
 
 
177
        sec_process_mcs_data(s);
 
178
        /*
 
179
           if (length > mcs_data->size)
 
180
           {
 
181
           error("MCS data length %d, expected %d\n", length,
 
182
           mcs_data->size);
 
183
           length = mcs_data->size;
 
184
           }
 
185
 
 
186
           in_uint8a(s, mcs_data->data, length);
 
187
           mcs_data->p = mcs_data->data;
 
188
           mcs_data->end = mcs_data->data + length;
 
189
         */
 
190
        return s_check_end(s);
 
191
}
 
192
 
 
193
/* Send an EDrq message (ASN.1 PER) */
 
194
static void
 
195
mcs_send_edrq(void)
 
196
{
 
197
        STREAM s;
 
198
 
 
199
        s = iso_init(5);
 
200
 
 
201
        out_uint8(s, (MCS_EDRQ << 2));
 
202
        out_uint16_be(s, 1);    /* height */
 
203
        out_uint16_be(s, 1);    /* interval */
 
204
 
 
205
        s_mark_end(s);
 
206
        iso_send(s);
 
207
}
 
208
 
 
209
/* Send an AUrq message (ASN.1 PER) */
 
210
static void
 
211
mcs_send_aurq(void)
 
212
{
 
213
        STREAM s;
 
214
 
 
215
        s = iso_init(1);
 
216
 
 
217
        out_uint8(s, (MCS_AURQ << 2));
 
218
 
 
219
        s_mark_end(s);
 
220
        iso_send(s);
 
221
}
 
222
 
 
223
/* Expect a AUcf message (ASN.1 PER) */
 
224
static BOOL
 
225
mcs_recv_aucf(uint16 * mcs_userid)
 
226
{
 
227
        uint8 opcode, result;
 
228
        STREAM s;
 
229
 
 
230
        s = iso_recv();
 
231
        if (s == NULL)
 
232
                return False;
 
233
 
 
234
        in_uint8(s, opcode);
 
235
        if ((opcode >> 2) != MCS_AUCF)
 
236
        {
 
237
                error("expected AUcf, got %d\n", opcode);
 
238
                return False;
 
239
        }
 
240
 
 
241
        in_uint8(s, result);
 
242
        if (result != 0)
 
243
        {
 
244
                error("AUrq: %d\n", result);
 
245
                return False;
 
246
        }
 
247
 
 
248
        if (opcode & 2)
 
249
                in_uint16_be(s, *mcs_userid);
 
250
 
 
251
        return s_check_end(s);
 
252
}
 
253
 
 
254
/* Send a CJrq message (ASN.1 PER) */
 
255
static void
 
256
mcs_send_cjrq(uint16 chanid)
 
257
{
 
258
        STREAM s;
 
259
 
 
260
        DEBUG_RDP5(("Sending CJRQ for channel #%d\n", chanid));
 
261
 
 
262
        s = iso_init(5);
 
263
 
 
264
        out_uint8(s, (MCS_CJRQ << 2));
 
265
        out_uint16_be(s, g_mcs_userid);
 
266
        out_uint16_be(s, chanid);
 
267
 
 
268
        s_mark_end(s);
 
269
        iso_send(s);
 
270
}
 
271
 
 
272
/* Expect a CJcf message (ASN.1 PER) */
 
273
static BOOL
 
274
mcs_recv_cjcf(void)
 
275
{
 
276
        uint8 opcode, result;
 
277
        STREAM s;
 
278
 
 
279
        s = iso_recv();
 
280
        if (s == NULL)
 
281
                return False;
 
282
 
 
283
        in_uint8(s, opcode);
 
284
        if ((opcode >> 2) != MCS_CJCF)
 
285
        {
 
286
                error("expected CJcf, got %d\n", opcode);
 
287
                return False;
 
288
        }
 
289
 
 
290
        in_uint8(s, result);
 
291
        if (result != 0)
 
292
        {
 
293
                error("CJrq: %d\n", result);
 
294
                return False;
 
295
        }
 
296
 
 
297
        in_uint8s(s, 4);        /* mcs_userid, req_chanid */
 
298
        if (opcode & 2)
 
299
                in_uint8s(s, 2);        /* join_chanid */
 
300
 
 
301
        return s_check_end(s);
 
302
}
 
303
 
 
304
/* Initialise an MCS transport data packet */
 
305
STREAM
 
306
mcs_init(int length)
 
307
{
 
308
        STREAM s;
 
309
 
 
310
        s = iso_init(length + 8);
 
311
        s_push_layer(s, mcs_hdr, 8);
 
312
 
 
313
        return s;
 
314
}
 
315
 
 
316
/* Send an MCS transport data packet to a specific channel */
 
317
void
 
318
mcs_send_to_channel(STREAM s, uint16 channel)
 
319
{
 
320
        uint16 length;
 
321
 
 
322
        s_pop_layer(s, mcs_hdr);
 
323
        length = s->end - s->p - 8;
 
324
        length |= 0x8000;
 
325
 
 
326
        out_uint8(s, (MCS_SDRQ << 2));
 
327
        out_uint16_be(s, g_mcs_userid);
 
328
        out_uint16_be(s, channel);
 
329
        out_uint8(s, 0x70);     /* flags */
 
330
        out_uint16_be(s, length);
 
331
 
 
332
        iso_send(s);
 
333
}
 
334
 
 
335
/* Send an MCS transport data packet to the global channel */
 
336
void
 
337
mcs_send(STREAM s)
 
338
{
 
339
        mcs_send_to_channel(s, MCS_GLOBAL_CHANNEL);
 
340
}
 
341
 
 
342
/* Receive an MCS transport data packet */
 
343
STREAM
 
344
mcs_recv(uint16 * channel)
 
345
{
 
346
        uint8 opcode, appid, length;
 
347
        STREAM s;
 
348
 
 
349
        s = iso_recv();
 
350
        if (s == NULL)
 
351
                return NULL;
 
352
 
 
353
        in_uint8(s, opcode);
 
354
        appid = opcode >> 2;
 
355
        if (appid != MCS_SDIN)
 
356
        {
 
357
                if (appid != MCS_DPUM)
 
358
                {
 
359
                        error("expected data, got %d\n", opcode);
 
360
                }
 
361
                return NULL;
 
362
        }
 
363
 
 
364
        in_uint8s(s, 2);        /* userid */
 
365
        in_uint16_be(s, *channel);
 
366
        in_uint8s(s, 1);        /* flags */
 
367
        in_uint8(s, length);
 
368
        if (length & 0x80)
 
369
                in_uint8s(s, 1);        /* second byte of length */
 
370
 
 
371
        return s;
 
372
}
 
373
 
 
374
/* Establish a connection up to the MCS layer */
 
375
BOOL
 
376
mcs_connect(char *server, STREAM mcs_data, char *username)
 
377
{
 
378
        unsigned int i;
 
379
 
 
380
        if (!iso_connect(server, username))
 
381
                return False;
 
382
 
 
383
        mcs_send_connect_initial(mcs_data);
 
384
        if (!mcs_recv_connect_response(mcs_data))
 
385
                goto error;
 
386
 
 
387
        mcs_send_edrq();
 
388
 
 
389
        mcs_send_aurq();
 
390
        if (!mcs_recv_aucf(&g_mcs_userid))
 
391
                goto error;
 
392
 
 
393
        mcs_send_cjrq(g_mcs_userid + MCS_USERCHANNEL_BASE);
 
394
 
 
395
        if (!mcs_recv_cjcf())
 
396
                goto error;
 
397
 
 
398
        mcs_send_cjrq(MCS_GLOBAL_CHANNEL);
 
399
        if (!mcs_recv_cjcf())
 
400
                goto error;
 
401
 
 
402
        for (i = 0; i < g_num_channels; i++)
 
403
        {
 
404
                mcs_send_cjrq(g_channels[i].mcs_id);
 
405
                if (!mcs_recv_cjcf())
 
406
                        goto error;
 
407
        }
 
408
        return True;
 
409
 
 
410
      error:
 
411
        iso_disconnect();
 
412
        return False;
 
413
}
 
414
 
 
415
/* Disconnect from the MCS layer */
 
416
void
 
417
mcs_disconnect(void)
 
418
{
 
419
        iso_disconnect();
 
420
}