1 /* -*- c-basic-offset: 8 -*- 2 rdesktop: A Remote Desktop Protocol client. 3 Protocol services - Multipoint Communications Service 4 Copyright (C) Matthew Chapman 1999-2005 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 along 17 with this program; if not, write to the Free Software Foundation, Inc., 18 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 19 */ 20 21 #include "rdesktop.h" 22 23 /* Parse an ASN.1 BER header */ 24 static BOOL 25 ber_parse_header(STREAM s, int tagval, int *length) 26 { 27 int tag, len; 28 29 if (tagval > 0xff) 30 { 31 in_uint16_be(s, tag); 32 } 33 else 34 { 35 in_uint8(s, tag)} 36 37 if (tag != tagval) 38 { 39 error("expected tag %d, got %d\n", tagval, tag); 40 return False; 41 } 42 43 in_uint8(s, len); 44 45 if (len & 0x80) 46 { 47 len &= ~0x80; 48 *length = 0; 49 while (len--) 50 next_be(s, *length); 51 } 52 else 53 *length = len; 54 55 return s_check(s); 56 } 57 58 /* Output an ASN.1 BER header */ 59 static void 60 ber_out_header(STREAM s, int tagval, int length) 61 { 62 if (tagval > 0xff) 63 { 64 out_uint16_be(s, tagval); 65 } 66 else 67 { 68 out_uint8(s, tagval); 69 } 70 71 if (length >= 0x80) 72 { 73 out_uint8(s, 0x82); 74 out_uint16_be(s, length); 75 } 76 else 77 out_uint8(s, length); 78 } 79 80 /* Output an ASN.1 BER integer */ 81 static void 82 ber_out_integer(STREAM s, int value) 83 { 84 ber_out_header(s, BER_TAG_INTEGER, 2); 85 out_uint16_be(s, value); 86 } 87 88 /* Output a DOMAIN_PARAMS structure (ASN.1 BER) */ 89 static void 90 mcs_out_domain_params(STREAM s, int max_channels, int max_users, int max_tokens, int max_pdusize) 91 { 92 ber_out_header(s, MCS_TAG_DOMAIN_PARAMS, 32); 93 ber_out_integer(s, max_channels); 94 ber_out_integer(s, max_users); 95 ber_out_integer(s, max_tokens); 96 ber_out_integer(s, 1); /* num_priorities */ 97 ber_out_integer(s, 0); /* min_throughput */ 98 ber_out_integer(s, 1); /* max_height */ 99 ber_out_integer(s, max_pdusize); 100 ber_out_integer(s, 2); /* ver_protocol */ 101 } 102 103 /* Parse a DOMAIN_PARAMS structure (ASN.1 BER) */ 104 static BOOL 105 mcs_parse_domain_params(STREAM s) 106 { 107 int length; 108 109 ber_parse_header(s, MCS_TAG_DOMAIN_PARAMS, &length); 110 in_uint8s(s, length); 111 112 return s_check(s); 113 } 114 115 /* Send an MCS_CONNECT_INITIAL message (ASN.1 BER) */ 116 static BOOL 117 mcs_send_connect_initial(RDPCLIENT * This, STREAM mcs_data) 118 { 119 int datalen = (uint16)(mcs_data->end - mcs_data->data); 120 int length = 9 + 3 * 34 + 4 + datalen; 121 STREAM s; 122 123 s = iso_init(This, length + 5); 124 125 if(s == NULL) 126 return False; 127 128 ber_out_header(s, MCS_CONNECT_INITIAL, length); 129 ber_out_header(s, BER_TAG_OCTET_STRING, 1); /* calling domain */ 130 out_uint8(s, 1); 131 ber_out_header(s, BER_TAG_OCTET_STRING, 1); /* called domain */ 132 out_uint8(s, 1); 133 134 ber_out_header(s, BER_TAG_BOOLEAN, 1); 135 out_uint8(s, 0xff); /* upward flag */ 136 137 mcs_out_domain_params(s, 34, 2, 0, 0xffff); /* target params */ 138 mcs_out_domain_params(s, 1, 1, 1, 0x420); /* min params */ 139 mcs_out_domain_params(s, 0xffff, 0xfc17, 0xffff, 0xffff); /* max params */ 140 141 ber_out_header(s, BER_TAG_OCTET_STRING, datalen); 142 out_uint8p(s, mcs_data->data, datalen); 143 144 s_mark_end(s); 145 return iso_send(This, s); 146 } 147 148 /* Expect a MCS_CONNECT_RESPONSE message (ASN.1 BER) */ 149 static BOOL 150 mcs_recv_connect_response(RDPCLIENT * This, STREAM mcs_data) 151 { 152 uint8 result; 153 int length; 154 STREAM s; 155 156 s = iso_recv(This, NULL); 157 if (s == NULL) 158 return False; 159 160 ber_parse_header(s, MCS_CONNECT_RESPONSE, &length); 161 162 ber_parse_header(s, BER_TAG_RESULT, &length); 163 in_uint8(s, result); 164 if (result != 0) 165 { 166 error("MCS connect: %d\n", result); 167 return False; 168 } 169 170 ber_parse_header(s, BER_TAG_INTEGER, &length); 171 in_uint8s(s, length); /* connect id */ 172 mcs_parse_domain_params(s); 173 174 ber_parse_header(s, BER_TAG_OCTET_STRING, &length); 175 176 sec_process_mcs_data(This, s); 177 /* 178 if (length > mcs_data->size) 179 { 180 error("MCS data length %d, expected %d\n", length, 181 mcs_data->size); 182 length = mcs_data->size; 183 } 184 185 in_uint8a(s, mcs_data->data, length); 186 mcs_data->p = mcs_data->data; 187 mcs_data->end = mcs_data->data + length; 188 */ 189 return s_check_end(s); 190 } 191 192 /* Send an EDrq message (ASN.1 PER) */ 193 static BOOL 194 mcs_send_edrq(RDPCLIENT * This) 195 { 196 STREAM s; 197 198 s = iso_init(This, 5); 199 200 if(s == NULL) 201 return False; 202 203 out_uint8(s, (MCS_EDRQ << 2)); 204 out_uint16_be(s, 1); /* height */ 205 out_uint16_be(s, 1); /* interval */ 206 207 s_mark_end(s); 208 return iso_send(This, s); 209 } 210 211 /* Send an AUrq message (ASN.1 PER) */ 212 static BOOL 213 mcs_send_aurq(RDPCLIENT * This) 214 { 215 STREAM s; 216 217 s = iso_init(This, 1); 218 219 if(s == NULL) 220 return False; 221 222 out_uint8(s, (MCS_AURQ << 2)); 223 224 s_mark_end(s); 225 return iso_send(This, s); 226 } 227 228 /* Expect a AUcf message (ASN.1 PER) */ 229 static BOOL 230 mcs_recv_aucf(RDPCLIENT * This, uint16 * mcs_userid) 231 { 232 uint8 opcode, result; 233 STREAM s; 234 235 s = iso_recv(This, NULL); 236 if (s == NULL) 237 return False; 238 239 in_uint8(s, opcode); 240 if ((opcode >> 2) != MCS_AUCF) 241 { 242 error("expected AUcf, got %d\n", opcode); 243 return False; 244 } 245 246 in_uint8(s, result); 247 if (result != 0) 248 { 249 error("AUrq: %d\n", result); 250 return False; 251 } 252 253 if (opcode & 2) 254 in_uint16_be(s, *mcs_userid); 255 256 return s_check_end(s); 257 } 258 259 /* Send a CJrq message (ASN.1 PER) */ 260 static BOOL 261 mcs_send_cjrq(RDPCLIENT * This, uint16 chanid) 262 { 263 STREAM s; 264 265 DEBUG_RDP5(("Sending CJRQ for channel #%d\n", chanid)); 266 267 s = iso_init(This, 5); 268 269 if(s == NULL) 270 return False; 271 272 out_uint8(s, (MCS_CJRQ << 2)); 273 out_uint16_be(s, This->mcs_userid); 274 out_uint16_be(s, chanid); 275 276 s_mark_end(s); 277 return iso_send(This, s); 278 } 279 280 /* Expect a CJcf message (ASN.1 PER) */ 281 static BOOL 282 mcs_recv_cjcf(RDPCLIENT * This) 283 { 284 uint8 opcode, result; 285 STREAM s; 286 287 s = iso_recv(This, NULL); 288 if (s == NULL) 289 return False; 290 291 in_uint8(s, opcode); 292 if ((opcode >> 2) != MCS_CJCF) 293 { 294 error("expected CJcf, got %d\n", opcode); 295 return False; 296 } 297 298 in_uint8(s, result); 299 if (result != 0) 300 { 301 error("CJrq: %d\n", result); 302 return False; 303 } 304 305 in_uint8s(s, 4); /* mcs_userid, req_chanid */ 306 if (opcode & 2) 307 in_uint8s(s, 2); /* join_chanid */ 308 309 return s_check_end(s); 310 } 311 312 /* Initialise an MCS transport data packet */ 313 STREAM 314 mcs_init(RDPCLIENT * This, int length) 315 { 316 STREAM s; 317 318 s = iso_init(This, length + 8); 319 320 if(s == NULL) 321 return NULL; 322 323 s_push_layer(s, mcs_hdr, 8); 324 325 return s; 326 } 327 328 /* Send an MCS transport data packet to a specific channel */ 329 BOOL 330 mcs_send_to_channel(RDPCLIENT * This, STREAM s, uint16 channel) 331 { 332 uint16 length; 333 334 s_pop_layer(s, mcs_hdr); 335 length = (uint16)(s->end - s->p - 8); 336 length |= 0x8000; 337 338 out_uint8(s, (MCS_SDRQ << 2)); 339 out_uint16_be(s, This->mcs_userid); 340 out_uint16_be(s, channel); 341 out_uint8(s, 0x70); /* flags */ 342 out_uint16_be(s, length); 343 344 return iso_send(This, s); 345 } 346 347 /* Send an MCS transport data packet to the global channel */ 348 BOOL 349 mcs_send(RDPCLIENT * This, STREAM s) 350 { 351 return mcs_send_to_channel(This, s, MCS_GLOBAL_CHANNEL); 352 } 353 354 /* Receive an MCS transport data packet */ 355 STREAM 356 mcs_recv(RDPCLIENT * This, uint16 * channel, uint8 * rdpver) 357 { 358 uint8 opcode, appid, length; 359 STREAM s; 360 361 s = iso_recv(This, rdpver); 362 if (s == NULL) 363 return NULL; 364 if (rdpver != NULL) 365 if (*rdpver != 3) 366 return s; 367 in_uint8(s, opcode); 368 appid = opcode >> 2; 369 if (appid != MCS_SDIN) 370 { 371 if (appid != MCS_DPUM) 372 { 373 error("expected data, got %d\n", opcode); 374 } 375 return NULL; 376 } 377 in_uint8s(s, 2); /* userid */ 378 in_uint16_be(s, *channel); 379 in_uint8s(s, 1); /* flags */ 380 in_uint8(s, length); 381 if (length & 0x80) 382 in_uint8s(s, 1); /* second byte of length */ 383 return s; 384 } 385 386 /* Establish a connection up to the MCS layer */ 387 BOOL 388 mcs_connect(RDPCLIENT * This, char *server, char * cookie, STREAM mcs_data) 389 { 390 unsigned int i; 391 392 if (!iso_connect(This, server, cookie)) 393 return False; 394 395 if (!mcs_send_connect_initial(This, mcs_data) || !mcs_recv_connect_response(This, mcs_data)) 396 goto error; 397 398 if (!mcs_send_edrq(This) || !mcs_send_aurq(This)) 399 goto error; 400 401 if (!mcs_recv_aucf(This, &This->mcs_userid)) 402 goto error; 403 404 if (!mcs_send_cjrq(This, This->mcs_userid + MCS_USERCHANNEL_BASE) || !mcs_recv_cjcf(This)) 405 goto error; 406 407 if (!mcs_send_cjrq(This, MCS_GLOBAL_CHANNEL) || !mcs_recv_cjcf(This)) 408 goto error; 409 410 for (i = 0; i < This->num_channels; i++) 411 { 412 if (!mcs_send_cjrq(This, MCS_GLOBAL_CHANNEL + 1 + i) || !mcs_recv_cjcf(This)) 413 goto error; 414 } 415 return True; 416 417 error: 418 iso_disconnect(This); 419 return False; 420 } 421 422 /* Establish a connection up to the MCS layer */ 423 BOOL 424 mcs_reconnect(RDPCLIENT * This, char *server, char *cookie, STREAM mcs_data) 425 { 426 unsigned int i; 427 428 if (!iso_reconnect(This, server, cookie)) 429 return False; 430 431 if (!mcs_send_connect_initial(This, mcs_data) || !mcs_recv_connect_response(This, mcs_data)) 432 goto error; 433 434 if (!mcs_send_edrq(This) || !mcs_send_aurq(This)) 435 goto error; 436 437 if (!mcs_recv_aucf(This, &This->mcs_userid)) 438 goto error; 439 440 if (!mcs_send_cjrq(This, This->mcs_userid + MCS_USERCHANNEL_BASE) || !mcs_recv_cjcf(This)) 441 goto error; 442 443 if (!mcs_send_cjrq(This, MCS_GLOBAL_CHANNEL) || !mcs_recv_cjcf(This)) 444 goto error; 445 446 for (i = 0; i < This->num_channels; i++) 447 { 448 if (!mcs_send_cjrq(This, MCS_GLOBAL_CHANNEL + 1 + i) || !mcs_recv_cjcf(This)) 449 goto error; 450 } 451 return True; 452 453 error: 454 iso_disconnect(This); 455 return False; 456 } 457 458 /* Disconnect from the MCS layer */ 459 void 460 mcs_disconnect(RDPCLIENT * This) 461 { 462 iso_disconnect(This); 463 } 464 465 /* reset the state of the mcs layer */ 466 void 467 mcs_reset_state(RDPCLIENT * This) 468 { 469 This->mcs_userid = 0; 470 iso_reset_state(This); 471 } 472