Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

mcs.cpp

Go to the documentation of this file.
00001 /*
00002    rdesktop: A Remote Desktop Protocol client.
00003    Protocol services - Multipoint Communications Service
00004    Copyright (C) Matthew Chapman 1999-2002
00005    
00006    This program is free software; you can redistribute it and/or modify
00007    it under the terms of the GNU General Public License as published by
00008    the Free Software Foundation; either version 2 of the License, or
00009    (at your option) any later version.
00010    
00011    This program is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014    GNU General Public License for more details.
00015 
00016    You should have received a copy of the GNU General Public License
00017    along with this program; if not, write to the Free Software
00018    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00019 */
00020 
00021 #include "rdesktop.h"
00022 
00023 uint16 mcs_userid;
00024 
00025 /* Parse an ASN.1 BER header */
00026 static BOOL
00027 ber_parse_header(STREAM s, int tagval, unsigned int *length)
00028 {
00029         int tag, len;
00030 
00031         if (tagval > 0xff)
00032         {
00033                 in_uint16_be(s, tag);
00034         }
00035         else
00036         {
00037         in_uint8(s, tag)}
00038 
00039         if (tag != tagval)
00040         {
00041                 error("expected tag %d, got %d\n", tagval, tag);
00042                 return False;
00043         }
00044 
00045         in_uint8(s, len);
00046 
00047         if (len & 0x80)
00048         {
00049                 len &= ~0x80;
00050                 *length = 0;
00051                 while (len--)
00052                         next_be(s, *length);
00053         }
00054         else
00055                 *length = len;
00056 
00057         return s_check(s);
00058 }
00059 
00060 /* Output an ASN.1 BER header */
00061 static void
00062 ber_out_header(STREAM s, int tagval, int length)
00063 {
00064         if (tagval > 0xff)
00065         {
00066                 out_uint16_be(s, tagval);
00067         }
00068         else
00069         {
00070                 out_uint8(s, tagval);
00071         }
00072 
00073         if (length >= 0x80)
00074         {
00075                 out_uint8(s, 0x82);
00076                 out_uint16_be(s, length);
00077         }
00078         else
00079                 out_uint8(s, length);
00080 }
00081 
00082 /* Output an ASN.1 BER integer */
00083 static void
00084 ber_out_integer(STREAM s, int value)
00085 {
00086         ber_out_header(s, BER_TAG_INTEGER, 2);
00087         out_uint16_be(s, value);
00088 }
00089 
00090 /* Output a DOMAIN_PARAMS structure (ASN.1 BER) */
00091 static void
00092 mcs_out_domain_params(STREAM s, int max_channels, int max_users, int max_tokens, int max_pdusize)
00093 {
00094         ber_out_header(s, MCS_TAG_DOMAIN_PARAMS, 32);
00095         ber_out_integer(s, max_channels);
00096         ber_out_integer(s, max_users);
00097         ber_out_integer(s, max_tokens);
00098         ber_out_integer(s, 1);  /* num_priorities */
00099         ber_out_integer(s, 0);  /* min_throughput */
00100         ber_out_integer(s, 1);  /* max_height */
00101         ber_out_integer(s, max_pdusize);
00102         ber_out_integer(s, 2);  /* ver_protocol */
00103 }
00104 
00105 /* Parse a DOMAIN_PARAMS structure (ASN.1 BER) */
00106 static BOOL
00107 mcs_parse_domain_params(STREAM s)
00108 {
00109         unsigned int length;
00110 
00111         ber_parse_header(s, MCS_TAG_DOMAIN_PARAMS, &length);
00112         in_uint8s(s, length);
00113 
00114         return s_check(s);
00115 }
00116 
00117 /* Send an MCS_CONNECT_INITIAL message (ASN.1 BER) */
00118 static void
00119 mcs_send_connect_initial(STREAM mcs_data)
00120 {
00121         int datalen = mcs_data->end - mcs_data->data;
00122         int length = 7 + 3 * 34 + 4 + datalen;
00123         STREAM s;
00124 
00125         s = iso_init(length + 5);
00126 
00127         ber_out_header(s, MCS_CONNECT_INITIAL, length);
00128         ber_out_header(s, BER_TAG_OCTET_STRING, 0);     /* calling domain */
00129         ber_out_header(s, BER_TAG_OCTET_STRING, 0);     /* called domain */
00130 
00131         ber_out_header(s, BER_TAG_BOOLEAN, 1);
00132         out_uint8(s, 0xff);     /* upward flag */
00133 
00134         mcs_out_domain_params(s, 2, 2, 0, 0xffff);      /* target params */
00135         mcs_out_domain_params(s, 1, 1, 1, 0x420);       /* min params */
00136         mcs_out_domain_params(s, 0xffff, 0xfc17, 0xffff, 0xffff);       /* max params */
00137 
00138         ber_out_header(s, BER_TAG_OCTET_STRING, datalen);
00139         out_uint8p(s, mcs_data->data, datalen);
00140 
00141         s_mark_end(s);
00142         iso_send(s);
00143 }
00144 
00145 /* Expect a MCS_CONNECT_RESPONSE message (ASN.1 BER) */
00146 static BOOL
00147 mcs_recv_connect_response(STREAM mcs_data)
00148 {
00149         uint8 result;
00150         unsigned int length;
00151         STREAM s;
00152 
00153         s = iso_recv();
00154         if (s == NULL)
00155                 return False;
00156 
00157         ber_parse_header(s, MCS_CONNECT_RESPONSE, &length);
00158 
00159         ber_parse_header(s, BER_TAG_RESULT, &length);
00160         in_uint8(s, result);
00161         if (result != 0)
00162         {
00163                 error("MCS connect: %d\n", result);
00164                 return False;
00165         }
00166 
00167         ber_parse_header(s, BER_TAG_INTEGER, &length);
00168         in_uint8s(s, length);   /* connect id */
00169         mcs_parse_domain_params(s);
00170 
00171         ber_parse_header(s, BER_TAG_OCTET_STRING, &length);
00172         if (length > mcs_data->size)
00173         {
00174                 error("MCS data length %d\n", length);
00175                 length = mcs_data->size;
00176         }
00177 
00178         in_uint8a(s, mcs_data->data, length);
00179         mcs_data->p = mcs_data->data;
00180         mcs_data->end = mcs_data->data + length;
00181 
00182         return s_check_end(s);
00183 }
00184 
00185 /* Send an EDrq message (ASN.1 PER) */
00186 static void
00187 mcs_send_edrq(void)
00188 {
00189         STREAM s;
00190 
00191         s = iso_init(5);
00192 
00193         out_uint8(s, (MCS_EDRQ << 2));
00194         out_uint16_be(s, 1);    /* height */
00195         out_uint16_be(s, 1);    /* interval */
00196 
00197         s_mark_end(s);
00198         iso_send(s);
00199 }
00200 
00201 /* Send an AUrq message (ASN.1 PER) */
00202 static void
00203 mcs_send_aurq(void)
00204 {
00205         STREAM s;
00206 
00207         s = iso_init(1);
00208 
00209         out_uint8(s, (MCS_AURQ << 2));
00210 
00211         s_mark_end(s);
00212         iso_send(s);
00213 }
00214 
00215 /* Expect a AUcf message (ASN.1 PER) */
00216 static BOOL
00217 mcs_recv_aucf(uint16 * mcs_userid)
00218 {
00219         uint8 opcode, result;
00220         STREAM s;
00221 
00222         s = iso_recv();
00223         if (s == NULL)
00224                 return False;
00225 
00226         in_uint8(s, opcode);
00227         if ((opcode >> 2) != MCS_AUCF)
00228         {
00229                 error("expected AUcf, got %d\n", opcode);
00230                 return False;
00231         }
00232 
00233         in_uint8(s, result);
00234         if (result != 0)
00235         {
00236                 error("AUrq: %d\n", result);
00237                 return False;
00238         }
00239 
00240         if (opcode & 2)
00241                 in_uint16_be(s, *mcs_userid);
00242 
00243         return s_check_end(s);
00244 }
00245 
00246 /* Send a CJrq message (ASN.1 PER) */
00247 static void
00248 mcs_send_cjrq(uint16 chanid)
00249 {
00250         STREAM s;
00251 
00252         s = iso_init(5);
00253 
00254         out_uint8(s, (MCS_CJRQ << 2));
00255         out_uint16_be(s, mcs_userid);
00256         out_uint16_be(s, chanid);
00257 
00258         s_mark_end(s);
00259         iso_send(s);
00260 }
00261 
00262 /* Expect a CJcf message (ASN.1 PER) */
00263 static BOOL
00264 mcs_recv_cjcf(void)
00265 {
00266         uint8 opcode, result;
00267         STREAM s;
00268 
00269         s = iso_recv();
00270         if (s == NULL)
00271                 return False;
00272 
00273         in_uint8(s, opcode);
00274         if ((opcode >> 2) != MCS_CJCF)
00275         {
00276                 error("expected CJcf, got %d\n", opcode);
00277                 return False;
00278         }
00279 
00280         in_uint8(s, result);
00281         if (result != 0)
00282         {
00283                 error("CJrq: %d\n", result);
00284                 return False;
00285         }
00286 
00287         in_uint8s(s, 4);        /* mcs_userid, req_chanid */
00288         if (opcode & 2)
00289                 in_uint8s(s, 2);        /* join_chanid */
00290 
00291         return s_check_end(s);
00292 }
00293 
00294 /* Initialise an MCS transport data packet */
00295 STREAM
00296 mcs_init(int length)
00297 {
00298         STREAM s;
00299 
00300         s = iso_init(length + 8);
00301         s_push_layer(s, mcs_hdr, 8);
00302 
00303         return s;
00304 }
00305 
00306 /* Send an MCS transport data packet */
00307 void
00308 mcs_send(STREAM s)
00309 {
00310         uint16 length;
00311 
00312         s_pop_layer(s, mcs_hdr);
00313         length = s->end - s->p - 8;
00314         length |= 0x8000;
00315 
00316         out_uint8(s, (MCS_SDRQ << 2));
00317         out_uint16_be(s, mcs_userid);
00318         out_uint16_be(s, MCS_GLOBAL_CHANNEL);
00319         out_uint8(s, 0x70);     /* flags */
00320         out_uint16_be(s, length);
00321 
00322         iso_send(s);
00323 }
00324 
00325 /* Receive an MCS transport data packet */
00326 STREAM
00327 mcs_recv(void)
00328 {
00329         uint8 opcode, appid, length;
00330         STREAM s;
00331 
00332         s = iso_recv();
00333         if (s == NULL)
00334                 return NULL;
00335 
00336         in_uint8(s, opcode);
00337         appid = opcode >> 2;
00338         if (appid != MCS_SDIN)
00339         {
00340                 if (appid != MCS_DPUM)
00341                 {
00342                         error("expected data, got %d\n", opcode);
00343                 }
00344                 return NULL;
00345         }
00346 
00347         in_uint8s(s, 5);        /* userid, chanid, flags */
00348         in_uint8(s, length);
00349         if (length & 0x80)
00350                 in_uint8s(s, 1);        /* second byte of length */
00351 
00352         return s;
00353 }
00354 
00355 /* Establish a connection up to the MCS layer */
00356 BOOL
00357 mcs_connect(char *server, STREAM mcs_data)
00358 {
00359         if (!iso_connect(server))
00360         {
00361                 return False;
00362         }
00363 
00364         mcs_send_connect_initial(mcs_data);
00365         if (!mcs_recv_connect_response(mcs_data))
00366                 goto error;
00367 
00368         mcs_send_edrq();
00369 
00370         mcs_send_aurq();
00371         if (!mcs_recv_aucf(&mcs_userid))
00372                 goto error;
00373 
00374         mcs_send_cjrq(mcs_userid + 1001);
00375         if (!mcs_recv_cjcf())
00376                 goto error;
00377 
00378         mcs_send_cjrq(MCS_GLOBAL_CHANNEL);
00379         if (!mcs_recv_cjcf())
00380                 goto error;
00381 
00382         return True;
00383 
00384       error:
00385         iso_disconnect();
00386         return False;
00387 }
00388 
00389 /* Disconnect from the MCS layer */
00390 void
00391 mcs_disconnect(void)
00392 {
00393         iso_disconnect();
00394 }

Generated on Sat Nov 5 16:17:41 2005 for OPIE by  doxygen 1.4.2