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 7 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. 12 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. 17 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/>. 20 */ 21 22 #include "precomp.h" 23 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; 28 29 static RD_BOOL g_negotiate_rdp_protocol = True; 30 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; 35 36 37 /* Send a self-contained ISO PDU */ 38 static void 39 iso_send_msg(uint8 code) 40 { 41 STREAM s; 42 43 s = tcp_init(11); 44 45 out_uint8(s, 3); /* version */ 46 out_uint8(s, 0); /* reserved */ 47 out_uint16_be(s, 11); /* length */ 48 49 out_uint8(s, 6); /* hdrlen */ 50 out_uint8(s, code); 51 out_uint16(s, 0); /* dst_ref */ 52 out_uint16(s, 0); /* src_ref */ 53 out_uint8(s, 0); /* class */ 54 55 s_mark_end(s); 56 tcp_send(s); 57 } 58 59 static void 60 iso_send_connection_request(char *username, uint32 neg_proto) 61 { 62 STREAM s; 63 int length = 30 + strlen(username); 64 65 if (g_rdp_version >= RDP_V5 && g_negotiate_rdp_protocol) 66 length += 8; 67 68 s = tcp_init(length); 69 70 out_uint8(s, 3); /* version */ 71 out_uint8(s, 0); /* reserved */ 72 out_uint16_be(s, length); /* length */ 73 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 */ 79 80 out_uint8p(s, "Cookie: mstshash=", strlen("Cookie: mstshash=")); 81 out_uint8p(s, username, strlen(username)); 82 83 out_uint8(s, 0x0d); /* cookie termination string: CR+LF */ 84 out_uint8(s, 0x0a); 85 86 if (g_rdp_version >= RDP_V5 && g_negotiate_rdp_protocol) 87 { 88 /* optional rdp protocol negotiation request for RDPv5 */ 89 out_uint8(s, RDP_NEG_REQ); 90 out_uint8(s, 0); 91 out_uint16(s, 8); 92 out_uint32(s, neg_proto); 93 } 94 95 s_mark_end(s); 96 tcp_send(s); 97 } 98 99 /* Receive a message on the ISO layer, return code */ 100 static STREAM 101 iso_recv_msg(uint8 * code, uint8 * rdpver) 102 { 103 STREAM s; 104 uint16 length; 105 uint8 version; 106 107 s = tcp_recv(NULL, 4); 108 if (s == NULL) 109 return NULL; 110 in_uint8(s, version); 111 if (rdpver != NULL) 112 *rdpver = version; 113 if (version == 3) 114 { 115 in_uint8s(s, 1); /* pad */ 116 in_uint16_be(s, length); 117 } 118 else 119 { 120 in_uint8(s, length); 121 if (length & 0x80) 122 { 123 length &= ~0x80; 124 next_be(s, length); 125 } 126 } 127 if (length < 4) 128 { 129 error("Bad packet header\n"); 130 return NULL; 131 } 132 s = tcp_recv(s, length - 4); 133 if (s == NULL) 134 return NULL; 135 if (version != 3) 136 return s; 137 in_uint8s(s, 1); /* hdrlen */ 138 in_uint8(s, *code); 139 if (*code == ISO_PDU_DT) 140 { 141 in_uint8s(s, 1); /* eot */ 142 return s; 143 } 144 in_uint8s(s, 5); /* dst_ref, src_ref, class */ 145 return s; 146 } 147 148 /* Initialise ISO transport data packet */ 149 STREAM 150 iso_init(int length) 151 { 152 STREAM s; 153 154 s = tcp_init(length + 7); 155 s_push_layer(s, iso_hdr, 7); 156 157 return s; 158 } 159 160 /* Send an ISO data PDU */ 161 void 162 iso_send(STREAM s) 163 { 164 uint16 length; 165 166 s_pop_layer(s, iso_hdr); 167 length = s->end - s->p; 168 169 out_uint8(s, 3); /* version */ 170 out_uint8(s, 0); /* reserved */ 171 out_uint16_be(s, length); 172 173 out_uint8(s, 2); /* hdrlen */ 174 out_uint8(s, ISO_PDU_DT); /* code */ 175 out_uint8(s, 0x80); /* eot */ 176 177 tcp_send(s); 178 } 179 180 /* Receive ISO transport data packet */ 181 STREAM 182 iso_recv(uint8 * rdpver) 183 { 184 STREAM s; 185 uint8 code = 0; 186 187 s = iso_recv_msg(&code, rdpver); 188 if (s == NULL) 189 return NULL; 190 if (rdpver != NULL) 191 if (*rdpver != 3) 192 return s; 193 if (code != ISO_PDU_DT) 194 { 195 error("expected DT, got 0x%x\n", code); 196 return NULL; 197 } 198 return s; 199 } 200 201 /* Establish a connection up to the ISO layer */ 202 RD_BOOL 203 iso_connect(char *server, char *username, char *domain, char *password, 204 RD_BOOL reconnect, uint32 * selected_protocol) 205 { 206 STREAM s; 207 uint8 code; 208 uint32 neg_proto; 209 210 g_negotiate_rdp_protocol = True; 211 212 neg_proto = PROTOCOL_SSL; 213 214 #ifdef WITH_CREDSSP 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; 219 else 220 warning("Disables CredSSP due to missing smartcard information for SSO.\n"); 221 #endif 222 223 retry: 224 *selected_protocol = PROTOCOL_RDP; 225 code = 0; 226 227 if (!tcp_connect(server)) 228 return False; 229 230 iso_send_connection_request(username, neg_proto); 231 232 s = iso_recv_msg(&code, NULL); 233 if (s == NULL) 234 return False; 235 236 if (code != ISO_PDU_CC) 237 { 238 error("expected CC, got 0x%x\n", code); 239 tcp_disconnect(); 240 return False; 241 } 242 243 if (g_rdp_version >= RDP_V5 && s_check_rem(s, 8)) 244 { 245 /* handle RDP_NEG_REQ response */ 246 const char *reason = NULL; 247 248 uint8 type = 0, flags = 0; 249 uint16 length = 0; 250 uint32 data = 0; 251 252 in_uint8(s, type); 253 in_uint8(s, flags); 254 in_uint16(s, length); 255 in_uint32(s, data); 256 257 if (type == RDP_NEG_FAILURE) 258 { 259 RD_BOOL retry_without_neg = False; 260 261 switch (data) 262 { 263 case SSL_WITH_USER_AUTH_REQUIRED_BY_SERVER: 264 reason = "SSL with user authentication required by server"; 265 break; 266 case SSL_NOT_ALLOWED_BY_SERVER: 267 reason = "SSL not allowed by server"; 268 retry_without_neg = True; 269 break; 270 case SSL_CERT_NOT_ON_SERVER: 271 reason = "no valid authentication certificate on server"; 272 retry_without_neg = True; 273 break; 274 case INCONSISTENT_FLAGS: 275 reason = "inconsistent negotiation flags"; 276 break; 277 case SSL_REQUIRED_BY_SERVER: 278 reason = "SSL required by server"; 279 break; 280 case HYBRID_REQUIRED_BY_SERVER: 281 reason = "CredSSP required by server"; 282 break; 283 default: 284 reason = "unknown reason"; 285 } 286 287 tcp_disconnect(); 288 289 if (retry_without_neg) 290 { 291 fprintf(stderr, 292 "Failed to negotiate protocol, retrying with plain RDP.\n"); 293 g_negotiate_rdp_protocol = False; 294 goto retry; 295 } 296 297 fprintf(stderr, "Failed to connect, %s.\n", reason); 298 return False; 299 } 300 301 if (type != RDP_NEG_RSP) 302 { 303 tcp_disconnect(); 304 error("Expected RDP_NEG_RSP, got type = 0x%x\n", type); 305 return False; 306 } 307 308 /* handle negotiation response */ 309 if (data == PROTOCOL_SSL) 310 { 311 #ifdef WITH_SSL 312 if (!tcp_tls_connect()) 313 { 314 /* failed to connect using cssp, let retry with plain TLS */ 315 tcp_disconnect(); 316 neg_proto = PROTOCOL_RDP; 317 goto retry; 318 } 319 /* do not use encryption when using TLS */ 320 g_encryption = False; 321 fprintf(stderr, "Connection established using SSL.\n"); 322 #else /* WITH_SSL */ 323 fprintf(stderr, "SSL not compiled in.\n"); 324 #endif /* WITH_SSL */ 325 } 326 #ifdef WITH_CREDSSP 327 else if (data == PROTOCOL_HYBRID) 328 { 329 if (!cssp_connect(server, username, domain, password, s)) 330 { 331 /* failed to connect using cssp, let retry with plain TLS */ 332 tcp_disconnect(); 333 neg_proto = PROTOCOL_SSL; 334 goto retry; 335 } 336 337 /* do not use encryption when using TLS */ 338 fprintf(stderr, "Connection established using CredSSP.\n"); 339 g_encryption = False; 340 } 341 #endif 342 else if (data == PROTOCOL_RDP) 343 { 344 fprintf(stderr, "Connection established using plain RDP.\n"); 345 } 346 else if (data != PROTOCOL_RDP) 347 { 348 tcp_disconnect(); 349 error("Unexpected protocol in negotiation response, got data = 0x%x.\n", 350 data); 351 return False; 352 } 353 if (length || flags) {} 354 355 *selected_protocol = data; 356 } 357 return True; 358 } 359 360 /* Disconnect from the ISO layer */ 361 void 362 iso_disconnect(void) 363 { 364 iso_send_msg(ISO_PDU_DR); 365 tcp_disconnect(); 366 } 367 368 /* reset the state to support reconnecting */ 369 void 370 iso_reset_state(void) 371 { 372 g_encryption = g_encryption_initial; 373 tcp_reset_state(); 374 } 375