"Fossies" - the Fresh Open Source Software Archive

Member "rdesktop-1.9.0/iso.c" (20 Sep 2019, 9709 Bytes) of package /linux/privat/rdesktop-1.9.0.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "iso.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 1.8.3_vs_1.8.5.

    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-2018 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 "rdesktop.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 extern char g_tls_version[];
   36 
   37 
   38 /* Send a self-contained ISO PDU */
   39 static void
   40 iso_send_msg(uint8 code)
   41 {
   42     STREAM s;
   43 
   44     s = tcp_init(11);
   45 
   46     out_uint8(s, 3);    /* version */
   47     out_uint8(s, 0);    /* reserved */
   48     out_uint16_be(s, 11);   /* length */
   49 
   50     out_uint8(s, 6);    /* hdrlen */
   51     out_uint8(s, code);
   52     out_uint16(s, 0);   /* dst_ref */
   53     out_uint16(s, 0);   /* src_ref */
   54     out_uint8(s, 0);    /* class */
   55 
   56     s_mark_end(s);
   57     tcp_send(s);
   58     s_free(s);
   59 }
   60 
   61 static void
   62 iso_send_connection_request(char *username, uint32 neg_proto)
   63 {
   64     STREAM s;
   65     int length = 30 + strlen(username);
   66 
   67     if (g_rdp_version >= RDP_V5 && g_negotiate_rdp_protocol)
   68         length += 8;
   69 
   70     s = tcp_init(length);
   71 
   72     out_uint8(s, 3);    /* version */
   73     out_uint8(s, 0);    /* reserved */
   74     out_uint16_be(s, length);   /* length */
   75 
   76     out_uint8(s, length - 5);   /* hdrlen */
   77     out_uint8(s, ISO_PDU_CR);
   78     out_uint16(s, 0);   /* dst_ref */
   79     out_uint16(s, 0);   /* src_ref */
   80     out_uint8(s, 0);    /* class */
   81 
   82     out_uint8a(s, "Cookie: mstshash=", strlen("Cookie: mstshash="));
   83     out_uint8a(s, username, strlen(username));
   84 
   85     out_uint8(s, 0x0d); /* cookie termination string: CR+LF */
   86     out_uint8(s, 0x0a);
   87 
   88     if (g_rdp_version >= RDP_V5 && g_negotiate_rdp_protocol)
   89     {
   90         /* optional RDP protocol negotiation request for RDPv5 */
   91         out_uint8(s, RDP_NEG_REQ);
   92         out_uint8(s, 0);
   93         out_uint16(s, 8);
   94         out_uint32(s, neg_proto);
   95     }
   96 
   97     s_mark_end(s);
   98     tcp_send(s);
   99     s_free(s);
  100 }
  101 
  102 /* Receive a message on the ISO layer, return code */
  103 static STREAM
  104 iso_recv_msg(uint8 * code, RD_BOOL * is_fastpath, uint8 * fastpath_hdr)
  105 {
  106     STREAM s;
  107     uint16 length;
  108     uint8 version;
  109 
  110     s = tcp_recv(NULL, 4);
  111     if (s == NULL)
  112         return NULL;
  113 
  114     in_uint8(s, version);   /* T.123 version or Fastpath output header */
  115 
  116     /* detect if this is a slow or fast path PDU */
  117     *fastpath_hdr = 0x00;
  118     *is_fastpath = False;
  119     if (version == T123_HEADER_VERSION)
  120     {
  121         in_uint8s(s, 1);    /* reserved */
  122         in_uint16_be(s, length);    /* length */
  123     }
  124     else
  125     {
  126         /* if version is not an expected T.123 version eg. 3, then this
  127            stream is a fast path pdu */
  128         *is_fastpath = True;
  129         *fastpath_hdr = version;
  130         in_uint8(s, length);    /* length1 */
  131         if (length & 0x80)
  132         {
  133             /* length2 is only present if the most significant bit of length1 is set */
  134             length &= ~0x80;
  135             next_be(s, length);
  136         }
  137     }
  138 
  139     if (length < 4)
  140     {
  141         logger(Protocol, Error, "iso_recv_msg(), bad packet header, length < 4");
  142         return NULL;
  143     }
  144 
  145     s = tcp_recv(s, length - 4);
  146     if (s == NULL)
  147         return NULL;
  148 
  149     if (*is_fastpath == True)
  150         return s;
  151 
  152     in_uint8s(s, 1);    /* hdrlen */
  153     in_uint8(s, *code);
  154     if (*code == ISO_PDU_DT)
  155     {
  156         in_uint8s(s, 1);    /* eot */
  157         return s;
  158     }
  159     in_uint8s(s, 5);    /* dst_ref, src_ref, class */
  160     return s;
  161 }
  162 
  163 /* Initialise ISO transport data packet */
  164 STREAM
  165 iso_init(int length)
  166 {
  167     STREAM s;
  168 
  169     s = tcp_init(length + 7);
  170     s_push_layer(s, iso_hdr, 7);
  171 
  172     return s;
  173 }
  174 
  175 /* Send an ISO data PDU */
  176 void
  177 iso_send(STREAM s)
  178 {
  179     uint16 length;
  180 
  181     s_pop_layer(s, iso_hdr);
  182     length = s_remaining(s);
  183 
  184     out_uint8(s, T123_HEADER_VERSION);  /* version */
  185     out_uint8(s, 0);    /* reserved */
  186     out_uint16_be(s, length);
  187 
  188     out_uint8(s, 2);    /* hdrlen */
  189     out_uint8(s, ISO_PDU_DT);   /* code */
  190     out_uint8(s, 0x80); /* eot */
  191 
  192     tcp_send(s);
  193 }
  194 
  195 /* Receive ISO transport data packet */
  196 STREAM
  197 iso_recv(RD_BOOL * is_fastpath, uint8 * fastpath_hdr)
  198 {
  199     STREAM s;
  200     uint8 code = 0;
  201 
  202     s = iso_recv_msg(&code, is_fastpath, fastpath_hdr);
  203     if (s == NULL)
  204         return NULL;
  205 
  206     if (*is_fastpath == True)
  207         return s;
  208 
  209     if (code != ISO_PDU_DT)
  210     {
  211         logger(Protocol, Error, "iso_recv(), expected ISO_PDU_DT, got 0x%x", code);
  212         return NULL;
  213     }
  214     return s;
  215 }
  216 
  217 
  218 /* try to setup a more helpful error message about TLS */
  219 char *get_credSSP_reason(uint32 neg_proto)
  220 {
  221 static char msg[256];
  222 
  223 strcat(msg, "CredSSP required by server");
  224 if ((neg_proto & PROTOCOL_SSL) &&
  225     ( (g_tls_version[0] == 0) ||
  226          (strcmp(g_tls_version, "1.2") < 0)))
  227     strcat(msg, " (check if server has disabled old TLS versions, if yes use -V option)");
  228 return msg;
  229 }
  230 
  231 /* Establish a connection up to the ISO layer */
  232 RD_BOOL
  233 iso_connect(char *server, char *username, char *domain, char *password,
  234         RD_BOOL reconnect, uint32 * selected_protocol)
  235 {
  236     UNUSED(reconnect);
  237     STREAM s;
  238     uint8 code;
  239     uint32 neg_proto;
  240     RD_BOOL is_fastpath;
  241     uint8 fastpath_hdr;
  242 
  243     g_negotiate_rdp_protocol = True;
  244 
  245     neg_proto = PROTOCOL_SSL;
  246 
  247 #ifdef WITH_CREDSSP
  248     if (!g_use_password_as_pin)
  249         neg_proto |= PROTOCOL_HYBRID;
  250     else if (g_sc_csp_name || g_sc_reader_name || g_sc_card_name || g_sc_container_name)
  251         neg_proto |= PROTOCOL_HYBRID;
  252     else
  253         logger(Core, Warning,
  254                "iso_connect(), missing smartcard information for SSO, disabling CredSSP");
  255 #endif
  256     if (neg_proto & PROTOCOL_HYBRID)
  257         logger(Core, Verbose, "Connecting to server using NLA...");
  258     else
  259         logger(Core, Verbose, "Connecting to server using SSL...");
  260 
  261       retry:
  262     *selected_protocol = PROTOCOL_RDP;
  263     code = 0;
  264 
  265     if (!tcp_connect(server))
  266         return False;
  267 
  268     iso_send_connection_request(username, neg_proto);
  269 
  270     s = iso_recv_msg(&code, &is_fastpath, &fastpath_hdr);
  271     if (s == NULL)
  272         return False;
  273 
  274     if (code != ISO_PDU_CC)
  275     {
  276         logger(Protocol, Error, "iso_connect(), expected ISO_PDU_CC, got 0x%x", code);
  277         tcp_disconnect();
  278         return False;
  279     }
  280 
  281     if (g_rdp_version >= RDP_V5 && s_check_rem(s, 8))
  282     {
  283         /* handle RDP_NEG_REQ response */
  284         const char *reason = NULL;
  285 
  286         uint8 type = 0;
  287         uint32 data = 0;
  288 
  289         in_uint8(s, type);
  290         in_uint8s(s, 1);    /* skip flags */
  291         in_uint8s(s, 2);    /* skip length */
  292         in_uint32(s, data);
  293 
  294         if (type == RDP_NEG_FAILURE)
  295         {
  296             RD_BOOL retry_without_neg = False;
  297 
  298             switch (data)
  299             {
  300                 case SSL_WITH_USER_AUTH_REQUIRED_BY_SERVER:
  301                     reason = "SSL with user authentication required by server";
  302                     break;
  303                 case SSL_NOT_ALLOWED_BY_SERVER:
  304                     reason = "SSL not allowed by server";
  305                     retry_without_neg = True;
  306                     break;
  307                 case SSL_CERT_NOT_ON_SERVER:
  308                     reason = "no valid authentication certificate on server";
  309                     retry_without_neg = True;
  310                     break;
  311                 case INCONSISTENT_FLAGS:
  312                     reason = "inconsistent negotiation flags";
  313                     break;
  314                 case SSL_REQUIRED_BY_SERVER:
  315                     reason = "SSL required by server";
  316                     break;
  317                 case HYBRID_REQUIRED_BY_SERVER:
  318                     reason = get_credSSP_reason(neg_proto);
  319                     break;
  320                 default:
  321                     reason = "unknown reason";
  322             }
  323 
  324             tcp_disconnect();
  325 
  326             if (retry_without_neg)
  327             {
  328                 if (reason != NULL)
  329                 {
  330                     logger(Protocol, Warning,
  331                            "Protocol negotiation failed with reason: %s",
  332                            reason);
  333                 }
  334 
  335                 logger(Core, Notice, "Retrying with plain RDP.");
  336                 g_negotiate_rdp_protocol = False;
  337                 goto retry;
  338             }
  339 
  340             logger(Core, Notice, "Failed to connect, %s.\n", reason);
  341             return False;
  342         }
  343 
  344         if (type != RDP_NEG_RSP)
  345         {
  346             tcp_disconnect();
  347             logger(Protocol, Error, "iso_connect(), expected RDP_NEG_RSP, got 0x%x",
  348                    type);
  349             return False;
  350         }
  351 
  352         /* handle negotiation response */
  353         if (data == PROTOCOL_SSL)
  354         {
  355             if (!tcp_tls_connect())
  356             {
  357                 /* failed to connect using cssp, let retry with plain TLS */
  358                 logger(Core, Verbose,
  359                        "Failed to connect using SSL, trying with plain RDP.");
  360                 tcp_disconnect();
  361                 neg_proto = PROTOCOL_RDP;
  362                 goto retry;
  363             }
  364             /* do not use encryption when using TLS */
  365             g_encryption = False;
  366             logger(Core, Notice, "Connection established using SSL.");
  367         }
  368 #ifdef WITH_CREDSSP
  369         else if (data == PROTOCOL_HYBRID)
  370         {
  371             if (!cssp_connect(server, username, domain, password, s))
  372             {
  373                 /* failed to connect using cssp, let retry with plain TLS */
  374                 logger(Core, Verbose,
  375                        "Failed to connect using NLA, trying with SSL");
  376                 tcp_disconnect();
  377                 neg_proto = PROTOCOL_SSL;
  378                 goto retry;
  379             }
  380 
  381             /* do not use encryption when using TLS */
  382             logger(Core, Notice, "Connection established using CredSSP.");
  383             g_encryption = False;
  384         }
  385 #endif
  386         else if (data == PROTOCOL_RDP)
  387         {
  388             logger(Core, Notice, "Connection established using plain RDP.");
  389         }
  390         else if (data != PROTOCOL_RDP)
  391         {
  392             tcp_disconnect();
  393             logger(Protocol, Error,
  394                    "iso_connect(), unexpected protocol in negotiation response, got 0x%x",
  395                    data);
  396             return False;
  397         }
  398 
  399         *selected_protocol = data;
  400     }
  401     return True;
  402 }
  403 
  404 /* Disconnect from the ISO layer */
  405 void
  406 iso_disconnect(void)
  407 {
  408     iso_send_msg(ISO_PDU_DR);
  409     tcp_disconnect();
  410 }
  411 
  412 /* reset the state to support reconnecting */
  413 void
  414 iso_reset_state(void)
  415 {
  416     g_encryption = g_encryption_initial;
  417     tcp_reset_state();
  418 }