001: ///////////////////////////////////////////////////////////////////////////////
002: //
003: // This program is free software; you can redistribute it and/or modify
004: // it under the terms of the GNU General Public License and GNU Library
005: // General Public License as published by the Free Software Foundation;
006: // either version 2, or (at your option) any later version.
007: //
008: // This program is distributed in the hope that it will be useful,
009: // but WITHOUT ANY WARRANTY; without even the implied warranty of
010: // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
011: // GNU General Public License and GNU Library General Public License
012: // for more details.
013: //
014: // You should have received a copy of the GNU General Public License
015: // and GNU Library General Public License along with this program; if
016: // not, write to the Free Software Foundation, 675 Mass Ave, Cambridge,
017: // MA 02139, USA.
018: //
019: ///////////////////////////////////////////////////////////////////////////////
020:
021: package org.rdesktop.server.rdp;
022:
023: import java.io.*;
024: import java.net.*;
025:
026: import org.rdesktop.server.rdp.rdp5.VChannels;
027: import org.rdesktop.server.rdp.crypto.CryptoException;
028:
029: public class RdpMCS {
030: private static final int CONNECT_INITIAL = 0x7f65;
031: private static final int CONNECT_RESPONSE = 0x7f66;
032:
033: private static final int BER_TAG_BOOLEAN = 1;
034: private static final int BER_TAG_INTEGER = 2;
035: private static final int BER_TAG_OCTET_STRING = 4;
036: private static final int BER_TAG_RESULT = 10;
037: private static final int TAG_DOMAIN_PARAMS = 0x30;
038:
039: public static final int MCS_GLOBAL_CHANNEL = 1003;
040: public static final int MCS_USERCHANNEL_BASE = 1001;
041:
042: private static final int EDRQ = 1; /* Erect Domain Request */
043: private static final int DPUM = 8; /* Disconnect Provider Ultimatum */
044: private static final int AURQ = 10; /* Attach User Request */
045: private static final int AUCF = 11; /* Attach User Confirm */
046: private static final int CJRQ = 14; /* Channel Join Request */
047: private static final int CJCF = 15; /* Channel Join Confirm */
048: private static final int SDRQ = 25; /* Send Data Request */
049: private static final int SDIN = 26; /* Send Data Indication */
050:
051: private int m_McsUserID;
052: private VChannels m_channels;
053: private RdpProto m_rdpProto;
054: private RdpSecure m_secureLayer;
055: private RdpAbstractISO m_IsoLayer;
056:
057: public RdpMCS(VChannels channels, RdpProto rdpProto,
058: RdpSecure secureLayer) {
059: m_channels = channels;
060: m_rdpProto = rdpProto;
061: m_secureLayer = secureLayer;
062: m_IsoLayer = new RdpISO(rdpProto);
063: }
064:
065: private int berHeaderSize(int tagval, int length) {
066: int total = 0;
067: if (tagval > 0xff) {
068: total += 2;
069: } else {
070: total += 1;
071: }
072:
073: if (length >= 0x80) {
074: total += 3;
075: } else {
076: total += 1;
077: }
078:
079: return total;
080: }
081:
082: private int BERIntSize(int value) {
083: if (value > 0xff) {
084: return 4;
085: } else {
086: return 3;
087: }
088: }
089:
090: private int domainParamSize(int max_channels, int max_users,
091: int max_tokens, int max_pdusize) {
092: int endSize = BERIntSize(max_channels) + BERIntSize(max_users)
093: + BERIntSize(max_tokens) + BERIntSize(1)
094: + BERIntSize(0) + BERIntSize(1)
095: + BERIntSize(max_pdusize) + BERIntSize(2);
096: return berHeaderSize(TAG_DOMAIN_PARAMS, endSize) + endSize;
097: }
098:
099: public int available() throws java.io.IOException {
100: return m_IsoLayer.available();
101: }
102:
103: public void connect(RdpPacket data) throws IOException,
104: RdpDesktopException, RdpOrderException, CryptoException {
105: m_IsoLayer.connect();
106:
107: sendConnectInitial(data);
108: receiveConnectResponse(data);
109:
110: send_edrq();
111: send_aurq();
112:
113: m_McsUserID = receive_aucf();
114: send_cjrq(m_McsUserID + MCS_USERCHANNEL_BASE);
115: receive_cjcf();
116: send_cjrq(MCS_GLOBAL_CHANNEL);
117: receive_cjcf();
118:
119: for (int i = 0; i < m_channels.num_channels(); i++) {
120: send_cjrq(m_channels.mcs_id(i));
121: receive_cjcf();
122: }
123: }
124:
125: public void disconnect() {
126: m_IsoLayer.disconnect();
127: }
128:
129: public RdpPacket init(int length) throws RdpDesktopException {
130: RdpPacket data = m_IsoLayer.init(length + 8);
131: data.setHeader(RdpPacket.MCS_HEADER);
132: data.incrementPosition(8);
133: data.setStart(data.getPosition());
134: return data;
135: }
136:
137: public void send(RdpPacket buffer) throws RdpDesktopException,
138: IOException {
139: send_to_channel(buffer, MCS_GLOBAL_CHANNEL);
140: }
141:
142: public void send_to_channel(RdpPacket buffer, int channel)
143: throws RdpDesktopException, IOException {
144: int length = 0;
145: buffer.setPosition(buffer.getHeader(RdpPacket.MCS_HEADER));
146:
147: length = buffer.getEnd()
148: - buffer.getHeader(RdpPacket.MCS_HEADER) - 8;
149: length |= 0x8000;
150:
151: buffer.set8((SDRQ << 2));
152: buffer.setBigEndian16(m_McsUserID);
153: buffer.setBigEndian16(channel);
154: buffer.set8(0x70); //Flags
155: buffer.setBigEndian16(length);
156: m_IsoLayer.send(buffer);
157: }
158:
159: public RdpPacket receive(int[] channel) throws IOException,
160: RdpDesktopException, RdpOrderException, CryptoException {
161: int opcode = 0, appid = 0, length = 0;
162: RdpPacket buffer = m_IsoLayer.receive();
163: if (buffer == null) {
164: return null;
165: }
166:
167: buffer.setHeader(RdpPacket.MCS_HEADER);
168: opcode = buffer.get8();
169:
170: appid = opcode >> 2;
171:
172: if (appid != SDIN) {
173: if (appid != DPUM) {
174: throw new RdpDesktopException("Expected data got"
175: + opcode);
176: }
177:
178: throw new EOFException("End of transmission!");
179: }
180:
181: buffer.incrementPosition(2); // Skip UserID
182: channel[0] = buffer.getBigEndian16(); // Get ChannelID
183: buffer.incrementPosition(1); // Skip Flags
184:
185: length = buffer.get8();
186:
187: if ((length & 0x80) != 0) {
188: buffer.incrementPosition(1);
189: }
190:
191: buffer.setStart(buffer.getPosition());
192: return buffer;
193: }
194:
195: public void sendBerInteger(RdpPacket buffer, int value) {
196: int len = 1;
197:
198: if (value > 0xff) {
199: len = 2;
200: }
201:
202: sendBerHeader(buffer, BER_TAG_INTEGER, len);
203:
204: if (value > 0xff) {
205: buffer.setBigEndian16(value);
206: } else {
207: buffer.set8(value);
208: }
209: }
210:
211: public void sendBerHeader(RdpPacket buffer, int tagval, int length) {
212: if (tagval > 0xff) {
213: buffer.setBigEndian16(tagval);
214: } else {
215: buffer.set8(tagval);
216: }
217:
218: if (length >= 0x80) {
219: buffer.set8(0x82);
220: buffer.setBigEndian16(length);
221: } else {
222: buffer.set8(length);
223: }
224: }
225:
226: public void sendDomainParams(RdpPacket buffer, int max_channels,
227: int max_users, int max_tokens, int max_pdusize) {
228: int size = BERIntSize(max_channels) + BERIntSize(max_users)
229: + BERIntSize(max_tokens) + BERIntSize(1)
230: + BERIntSize(0) + BERIntSize(1)
231: + BERIntSize(max_pdusize) + BERIntSize(2);
232:
233: sendBerHeader(buffer, TAG_DOMAIN_PARAMS, size);
234: sendBerInteger(buffer, max_channels);
235: sendBerInteger(buffer, max_users);
236: sendBerInteger(buffer, max_tokens);
237:
238: sendBerInteger(buffer, 1); // num_priorities
239: sendBerInteger(buffer, 0); // min_throughput
240: sendBerInteger(buffer, 1); // max_height
241:
242: sendBerInteger(buffer, max_pdusize);
243: sendBerInteger(buffer, 2); // ver_protocol
244: }
245:
246: public void sendConnectInitial(RdpPacket data) throws IOException,
247: RdpDesktopException {
248: /*
249: int length = 7 + (3 *34) + 4 + data.getEnd();
250: RdpPacket buffer = m_IsoLayer.init(length+5);
251:
252: sendBerHeader(buffer, CONNECT_INITIAL, length);
253: sendBerHeader(buffer, BER_TAG_OCTET_STRING, 0); //calling domain
254: sendBerHeader(buffer, BER_TAG_OCTET_STRING, 0); // called domain
255:
256: sendBerHeader(buffer, BER_TAG_BOOLEAN, 1);
257: buffer.set8(255); //upward flag
258:
259: sendDomainParams(buffer, 2, 2, 0, 0xffff); //target parameters
260: sendDomainParams(buffer, 1, 1, 1, 0x420); // minimun parameters
261: sendDomainParams(buffer, 0xffff, 0xfc17, 0xffff, 0xffff); //maximum parameters
262:
263: sendBerHeader(buffer, BER_TAG_OCTET_STRING, data.getEnd());
264:
265: data.copyToPacket(buffer, 0, buffer.getPosition(), data.getEnd());
266: buffer.incrementPosition(data.getEnd());
267: buffer.markEnd();
268: m_IsoLayer.send(buffer);
269: */
270:
271: int datalen = data.getEnd();
272: int length = 9 + domainParamSize(34, 2, 0, 0xffff)
273: + domainParamSize(1, 1, 1, 0x420)
274: + domainParamSize(0xffff, 0xfc17, 0xffff, 0xffff) + 4
275: + datalen; // RDP5 Code
276:
277: RdpPacket buffer = m_IsoLayer.init(length + 5);
278:
279: sendBerHeader(buffer, CONNECT_INITIAL, length);
280: sendBerHeader(buffer, BER_TAG_OCTET_STRING, 1); //calling domain
281: buffer.set8(1); // RDP5 Code
282: sendBerHeader(buffer, BER_TAG_OCTET_STRING, 1); // called domain
283: buffer.set8(1); // RDP5 Code
284:
285: sendBerHeader(buffer, BER_TAG_BOOLEAN, 1);
286: buffer.set8(0xff); //upward flag
287:
288: sendDomainParams(buffer, 34, 2, 0, 0xffff); //target parameters // RDP5 Code
289: sendDomainParams(buffer, 1, 1, 1, 0x420); // minimum parameters
290: sendDomainParams(buffer, 0xffff, 0xfc17, 0xffff, 0xffff); //maximum parameters
291:
292: sendBerHeader(buffer, BER_TAG_OCTET_STRING, datalen);
293:
294: data.copyToPacket(buffer, 0, buffer.getPosition(), data
295: .getEnd());
296: buffer.incrementPosition(data.getEnd());
297: buffer.markEnd();
298: m_IsoLayer.send(buffer);
299: }
300:
301: public void receiveConnectResponse(RdpPacket data)
302: throws IOException, RdpDesktopException, RdpOrderException,
303: CryptoException {
304: String[] connect_results = { "Successful", "Domain Merging",
305: "Domain not Hierarchical", "No Such Channel",
306: "No Such Domain", "No Such User", "Not Admitted",
307: "Other User ID", "Parameters Unacceptable",
308: "Token Not Available", "Token Not Possessed",
309: "Too Many Channels", "Too Many Tokens",
310: "Too Many Users", "Unspecified Failure",
311: "User Rejected" };
312:
313: int result = 0;
314: int length = 0;
315:
316: RdpPacket buffer = m_IsoLayer.receive();
317: length = berParseHeader(buffer, CONNECT_RESPONSE);
318: length = berParseHeader(buffer, BER_TAG_RESULT);
319:
320: result = buffer.get8();
321: if (result != 0) {
322: throw new RdpDesktopException("MCS Connect failed: "
323: + connect_results[result]);
324: }
325:
326: length = berParseHeader(buffer, BER_TAG_INTEGER);
327: length = buffer.get8(); //connect id
328: parseDomainParams(buffer);
329: length = berParseHeader(buffer, BER_TAG_OCTET_STRING);
330:
331: m_secureLayer.processMcsData(buffer);
332:
333: /*
334: if (length > data.size())
335: {
336: length=data.size();
337: }
338:
339: data.copyFromPacket(buffer, buffer.getPosition(), 0, length);
340: data.setPosition(0);
341: data.markEnd(length);
342: buffer.incrementPosition(length);
343:
344: if (buffer.getPosition() != buffer.getEnd())
345: {
346: throw new RdpDesktopException();
347: }
348: */
349: }
350:
351: public void send_edrq() throws IOException, RdpDesktopException {
352: RdpPacket buffer = m_IsoLayer.init(5);
353: buffer.set8(EDRQ << 2);
354: buffer.setBigEndian16(1); //height
355: buffer.setBigEndian16(1); //interval
356: buffer.markEnd();
357: m_IsoLayer.send(buffer);
358: }
359:
360: public void send_cjrq(int channelid) throws IOException,
361: RdpDesktopException {
362: RdpPacket buffer = m_IsoLayer.init(5);
363: buffer.set8(CJRQ << 2);
364: buffer.setBigEndian16(m_McsUserID); //height
365: buffer.setBigEndian16(channelid); //interval
366: buffer.markEnd();
367: m_IsoLayer.send(buffer);
368: }
369:
370: public void send_aucf() throws IOException, RdpDesktopException {
371: RdpPacket buffer = m_IsoLayer.init(2);
372:
373: buffer.set8(AUCF << 2);
374: buffer.set8(0);
375: buffer.markEnd();
376: m_IsoLayer.send(buffer);
377: }
378:
379: public void send_aurq() throws IOException, RdpDesktopException {
380: RdpPacket buffer = m_IsoLayer.init(1);
381:
382: buffer.set8(AURQ << 2);
383: buffer.markEnd();
384: m_IsoLayer.send(buffer);
385: }
386:
387: public void receive_cjcf() throws IOException, RdpDesktopException,
388: RdpOrderException, CryptoException {
389: int opcode = 0;
390: int result = 0;
391: RdpPacket buffer = m_IsoLayer.receive();
392:
393: opcode = buffer.get8();
394: if ((opcode >> 2) != CJCF) {
395: throw new RdpDesktopException("Expected CJCF got" + opcode);
396: }
397:
398: result = buffer.get8();
399: if (result != 0) {
400: throw new RdpDesktopException("Expected CJRQ got " + result);
401: }
402:
403: buffer.incrementPosition(4); //skip userid, req_channelid
404:
405: if ((opcode & 2) != 0) {
406: buffer.incrementPosition(2); // skip join_channelid
407: }
408:
409: if (buffer.getPosition() != buffer.getEnd()) {
410: throw new RdpDesktopException();
411: }
412: }
413:
414: public int receive_aucf() throws IOException, RdpDesktopException,
415: RdpOrderException, CryptoException {
416: int opcode = 0;
417: int result = 0;
418: int UserID = 0;
419: RdpPacket buffer = m_IsoLayer.receive();
420:
421: opcode = buffer.get8();
422: if ((opcode >> 2) != AUCF) {
423: throw new RdpDesktopException("Expected AUCF got " + opcode);
424: }
425:
426: result = buffer.get8();
427: if (result != 0) {
428: throw new RdpDesktopException("Expected AURQ got " + result);
429: }
430:
431: if ((opcode & 2) != 0) {
432: UserID = buffer.getBigEndian16();
433: }
434:
435: if (buffer.getPosition() != buffer.getEnd()) {
436: throw new RdpDesktopException();
437: }
438:
439: return UserID;
440: }
441:
442: public int berParseHeader(RdpPacket data, int tagval)
443: throws RdpDesktopException {
444: int tag = 0;
445: int length = 0;
446: int len;
447:
448: if (tagval > 0x000000ff) {
449: tag = data.getBigEndian16();
450: } else {
451: tag = data.get8();
452: }
453:
454: if (tag != tagval) {
455: throw new RdpDesktopException("Unexpected tag got " + tag
456: + " expected " + tagval);
457: }
458:
459: len = data.get8();
460:
461: if ((len & 0x00000080) != 0) {
462: len &= ~0x00000080; // subtract 128
463: length = 0;
464:
465: while (len-- != 0) {
466: length = (length << 8) + data.get8();
467: }
468: } else {
469: length = len;
470: }
471:
472: return length;
473: }
474:
475: public void parseDomainParams(RdpPacket data)
476: throws RdpDesktopException {
477: int length = berParseHeader(data, TAG_DOMAIN_PARAMS);
478: data.incrementPosition(length);
479:
480: if (data.getPosition() > data.getEnd()) {
481: throw new RdpDesktopException();
482: }
483: }
484:
485: public int getUserID() {
486: return m_McsUserID;
487: }
488: }
|