1 /* -*- c-basic-offset: 8 -*-
2 rdesktop: A Remote Desktop Protocol client.
3 Protocol services - ISO layer
4 Copyright (C) Matthew Chapman <matthewc.unsw.edu.au> 1999-2008
5 Copyright 2005-2011 Peter Astrand <astrand@cendio.se> for Cendio AB
6 Copyright 2012 Henrik Andersson <hean01@cendio.se> for Cendio AB
8 This program is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 extern RD_BOOL g_encryption
;
25 extern RD_BOOL g_encryption_initial
;
26 extern RDP_VERSION g_rdp_version
;
27 extern RD_BOOL g_use_password_as_pin
;
29 static RD_BOOL g_negotiate_rdp_protocol
= True
;
31 extern char *g_sc_csp_name
;
32 extern char *g_sc_reader_name
;
33 extern char *g_sc_card_name
;
34 extern char *g_sc_container_name
;
37 /* Send a self-contained ISO PDU */
39 iso_send_msg(uint8 code
)
45 out_uint8(s
, 3); /* version */
46 out_uint8(s
, 0); /* reserved */
47 out_uint16_be(s
, 11); /* length */
49 out_uint8(s
, 6); /* hdrlen */
51 out_uint16(s
, 0); /* dst_ref */
52 out_uint16(s
, 0); /* src_ref */
53 out_uint8(s
, 0); /* class */
60 iso_send_connection_request(char *username
, uint32 neg_proto
)
63 int length
= 30 + strlen(username
);
65 if (g_rdp_version
>= RDP_V5
&& g_negotiate_rdp_protocol
)
70 out_uint8(s
, 3); /* version */
71 out_uint8(s
, 0); /* reserved */
72 out_uint16_be(s
, length
); /* length */
74 out_uint8(s
, length
- 5); /* hdrlen */
75 out_uint8(s
, ISO_PDU_CR
);
76 out_uint16(s
, 0); /* dst_ref */
77 out_uint16(s
, 0); /* src_ref */
78 out_uint8(s
, 0); /* class */
80 out_uint8p(s
, "Cookie: mstshash=", strlen("Cookie: mstshash="));
81 out_uint8p(s
, username
, strlen(username
));
83 out_uint8(s
, 0x0d); /* cookie termination string: CR+LF */
86 if (g_rdp_version
>= RDP_V5
&& g_negotiate_rdp_protocol
)
88 /* optional rdp protocol negotiation request for RDPv5 */
89 out_uint8(s
, RDP_NEG_REQ
);
92 out_uint32(s
, neg_proto
);
99 /* Receive a message on the ISO layer, return code */
101 iso_recv_msg(uint8
* code
, uint8
* rdpver
)
107 s
= tcp_recv(NULL
, 4);
110 in_uint8(s
, version
);
115 in_uint8s(s
, 1); /* pad */
116 in_uint16_be(s
, length
);
129 error("Bad packet header\n");
132 s
= tcp_recv(s
, length
- 4);
137 in_uint8s(s
, 1); /* hdrlen */
139 if (*code
== ISO_PDU_DT
)
141 in_uint8s(s
, 1); /* eot */
144 in_uint8s(s
, 5); /* dst_ref, src_ref, class */
148 /* Initialise ISO transport data packet */
154 s
= tcp_init(length
+ 7);
155 s_push_layer(s
, iso_hdr
, 7);
160 /* Send an ISO data PDU */
166 s_pop_layer(s
, iso_hdr
);
167 length
= s
->end
- s
->p
;
169 out_uint8(s
, 3); /* version */
170 out_uint8(s
, 0); /* reserved */
171 out_uint16_be(s
, length
);
173 out_uint8(s
, 2); /* hdrlen */
174 out_uint8(s
, ISO_PDU_DT
); /* code */
175 out_uint8(s
, 0x80); /* eot */
180 /* Receive ISO transport data packet */
182 iso_recv(uint8
* rdpver
)
187 s
= iso_recv_msg(&code
, rdpver
);
193 if (code
!= ISO_PDU_DT
)
195 error("expected DT, got 0x%x\n", code
);
201 /* Establish a connection up to the ISO layer */
203 iso_connect(char *server
, char *username
, char *domain
, char *password
,
204 RD_BOOL reconnect
, uint32
* selected_protocol
)
210 g_negotiate_rdp_protocol
= True
;
212 neg_proto
= PROTOCOL_SSL
;
215 if (!g_use_password_as_pin
)
216 neg_proto
|= PROTOCOL_HYBRID
;
217 else if (g_sc_csp_name
|| g_sc_reader_name
|| g_sc_card_name
|| g_sc_container_name
)
218 neg_proto
|= PROTOCOL_HYBRID
;
220 warning("Disables CredSSP due to missing smartcard information for SSO.\n");
224 *selected_protocol
= PROTOCOL_RDP
;
227 if (!tcp_connect(server
))
230 iso_send_connection_request(username
, neg_proto
);
232 s
= iso_recv_msg(&code
, NULL
);
236 if (code
!= ISO_PDU_CC
)
238 error("expected CC, got 0x%x\n", code
);
243 if (g_rdp_version
>= RDP_V5
&& s_check_rem(s
, 8))
245 /* handle RDP_NEG_REQ response */
246 const char *reason
= NULL
;
248 uint8 type
= 0, flags
= 0;
254 in_uint16(s
, length
);
257 if (type
== RDP_NEG_FAILURE
)
259 RD_BOOL retry_without_neg
= False
;
263 case SSL_WITH_USER_AUTH_REQUIRED_BY_SERVER
:
264 reason
= "SSL with user authentication required by server";
266 case SSL_NOT_ALLOWED_BY_SERVER
:
267 reason
= "SSL not allowed by server";
268 retry_without_neg
= True
;
270 case SSL_CERT_NOT_ON_SERVER
:
271 reason
= "no valid authentication certificate on server";
272 retry_without_neg
= True
;
274 case INCONSISTENT_FLAGS
:
275 reason
= "inconsistent negotiation flags";
277 case SSL_REQUIRED_BY_SERVER
:
278 reason
= "SSL required by server";
280 case HYBRID_REQUIRED_BY_SERVER
:
281 reason
= "CredSSP required by server";
284 reason
= "unknown reason";
289 if (retry_without_neg
)
292 "Failed to negotiate protocol, retrying with plain RDP.\n");
293 g_negotiate_rdp_protocol
= False
;
297 fprintf(stderr
, "Failed to connect, %s.\n", reason
);
301 if (type
!= RDP_NEG_RSP
)
304 error("Expected RDP_NEG_RSP, got type = 0x%x\n", type
);
308 /* handle negotiation response */
309 if (data
== PROTOCOL_SSL
)
312 if (!tcp_tls_connect())
314 /* failed to connect using cssp, let retry with plain TLS */
316 neg_proto
= PROTOCOL_RDP
;
319 /* do not use encryption when using TLS */
320 g_encryption
= False
;
321 fprintf(stderr
, "Connection established using SSL.\n");
323 fprintf(stderr
, "SSL not compiled in.\n");
324 #endif /* WITH_SSL */
327 else if (data
== PROTOCOL_HYBRID
)
329 if (!cssp_connect(server
, username
, domain
, password
, s
))
331 /* failed to connect using cssp, let retry with plain TLS */
333 neg_proto
= PROTOCOL_SSL
;
337 /* do not use encryption when using TLS */
338 fprintf(stderr
, "Connection established using CredSSP.\n");
339 g_encryption
= False
;
342 else if (data
== PROTOCOL_RDP
)
344 fprintf(stderr
, "Connection established using plain RDP.\n");
346 else if (data
!= PROTOCOL_RDP
)
349 error("Unexpected protocol in negotiation response, got data = 0x%x.\n",
353 if (length
|| flags
) {}
355 *selected_protocol
= data
;
360 /* Disconnect from the ISO layer */
364 iso_send_msg(ISO_PDU_DR
);
368 /* reset the state to support reconnecting */
370 iso_reset_state(void)
372 g_encryption
= g_encryption_initial
;