xrdp/libxrdp/xrdp_iso.c
Pavel Roskin d3c36b0376 Don't select SSL protocol if no keys, fall back to RDP for "hybrid"
If both the client and the server are configured to allow both RDP and
SSL connections, the server is free to choose RDP in absense of the SSL
keys.
2016-11-28 00:18:33 -08:00

430 lines
11 KiB
C

/**
* xrdp: A Remote Desktop Protocol server.
*
* Copyright (C) Jay Sorg 2004-2014
* Copyright (C) Idan Freiberg 2013-2014
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* iso layer
*/
#include "libxrdp.h"
#include "log.h"
#define LOG_LEVEL 1
#define LLOG(_level, _args) \
do { if (_level < LOG_LEVEL) { g_write _args ; } } while (0)
#define LLOGLN(_level, _args) \
do { if (_level < LOG_LEVEL) { g_writeln _args ; } } while (0)
#define LHEXDUMP(_level, _args) \
do { if (_level < LOG_LEVEL) { g_hexdump _args ; } } while (0)
/*****************************************************************************/
struct xrdp_iso *
APP_CC
xrdp_iso_create(struct xrdp_mcs *owner, struct trans *trans)
{
struct xrdp_iso *self;
LLOGLN(10, (" in xrdp_iso_create"));
self = (struct xrdp_iso *) g_malloc(sizeof(struct xrdp_iso), 1);
self->mcs_layer = owner;
self->trans = trans;
LLOGLN(10, (" out xrdp_iso_create"));
return self;
}
/*****************************************************************************/
void APP_CC
xrdp_iso_delete(struct xrdp_iso *self)
{
if (self == 0)
{
return;
}
g_free(self);
}
/*****************************************************************************/
/* returns error */
static int APP_CC
xrdp_iso_negotiate_security(struct xrdp_iso *self)
{
int rv = 0;
struct xrdp_client_info *client_info = &(self->mcs_layer->sec_layer->rdp_layer->client_info);
self->selectedProtocol = client_info->security_layer;
switch (client_info->security_layer)
{
case PROTOCOL_RDP:
break;
case PROTOCOL_SSL:
if (self->requestedProtocol & PROTOCOL_SSL)
{
if(!g_file_exist(client_info->certificate) ||
!g_file_exist(client_info->key_file))
{
/* certificate file doesn't exist */
LLOGLN(0, ("xrdp_iso_negotiate_security: TLS certificate not found on server"));
self->failureCode = SSL_CERT_NOT_ON_SERVER;
rv = 1; /* error */
}
else
{
self->selectedProtocol = PROTOCOL_SSL;
}
}
else
{
self->failureCode = SSL_REQUIRED_BY_SERVER;
rv = 1; /* error */
}
break;
case PROTOCOL_HYBRID:
case PROTOCOL_HYBRID_EX:
default:
if ((self->requestedProtocol & PROTOCOL_SSL) &&
g_file_exist(client_info->certificate) &&
g_file_exist(client_info->key_file))
{
/* that's a patch since we don't support CredSSP for now */
self->selectedProtocol = PROTOCOL_SSL;
}
else
{
self->selectedProtocol = PROTOCOL_RDP;
}
break;
}
log_message(LOG_LEVEL_DEBUG, "Security layer: requested %d, selected %d",
self->requestedProtocol, self->selectedProtocol);
return rv;
}
/*****************************************************************************/
/* returns error */
static int APP_CC
xrdp_iso_process_rdp_neg_req(struct xrdp_iso *self, struct stream *s)
{
int flags;
int len;
in_uint8(s, flags);
if (flags != 0x0 && flags != 0x8 && flags != 0x1)
{
LLOGLN(10, ("xrdp_iso_process_rdpNegReq: error, flags: %x",flags));
return 1;
}
in_uint16_le(s, len);
if (len != 8)
{
LLOGLN(10, ("xrdp_iso_process_rdpNegReq: error, length: %x",len));
return 1;
}
in_uint32_le(s, self->requestedProtocol);
if (self->requestedProtocol > 0xb)
{
LLOGLN(10, ("xrdp_iso_process_rdpNegReq: error, requestedProtocol: %x",
self->requestedProtocol));
return 1;
}
return 0;
}
/*****************************************************************************/
/* returns error */
static int APP_CC
xrdp_iso_recv_msg(struct xrdp_iso *self, struct stream *s, int *code, int *len)
{
int ver;
int plen;
*code = 0;
*len = 0;
if (s != self->trans->in_s)
{
LLOGLN(10, ("xrdp_iso_recv_msg error logic"));
}
in_uint8(s, ver);
if (ver != 3)
{
LLOGLN(10, ("xrdp_iso_recv_msg: bad ver"));
LHEXDUMP(10, (s->data, 4));
return 1;
}
in_uint8s(s, 1);
in_uint16_be(s, plen);
if (plen < 4)
{
return 1;
}
if (!s_check_rem(s, 2))
{
return 1;
}
in_uint8(s, *len);
in_uint8(s, *code);
if (*code == ISO_PDU_DT)
{
if (!s_check_rem(s, 1))
{
return 1;
}
in_uint8s(s, 1);
}
else
{
if (!s_check_rem(s, 5))
{
return 1;
}
in_uint8s(s, 5);
}
return 0;
}
/*****************************************************************************/
/* returns error */
int APP_CC
xrdp_iso_recv(struct xrdp_iso *self, struct stream *s)
{
int code;
int len;
LLOGLN(10, (" in xrdp_iso_recv"));
if (xrdp_iso_recv_msg(self, s, &code, &len) != 0)
{
LLOGLN(10, (" out xrdp_iso_recv xrdp_iso_recv_msg return non zero"));
return 1;
}
if (code != ISO_PDU_DT || len != 2)
{
LLOGLN(10, (" out xrdp_iso_recv code != ISO_PDU_DT or length != 2"));
return 1;
}
LLOGLN(10, (" out xrdp_iso_recv"));
return 0;
}
/*****************************************************************************/
static int APP_CC
xrdp_iso_send_cc(struct xrdp_iso *self)
{
struct stream *s;
char *holdp;
char *len_ptr;
char *len_indicator_ptr;
int len;
int len_indicator;
make_stream(s);
init_stream(s, 8192);
holdp = s->p;
/* tpkt */
out_uint8(s, 3); /* version */
out_uint8(s, 0); /* pad */
len_ptr = s->p;
out_uint16_be(s, 0); /* length, set later */
/* iso */
len_indicator_ptr = s->p;
out_uint8(s, 0); /* length indicator, set later */
out_uint8(s, ISO_PDU_CC); /* Connection Confirm PDU */
out_uint16_be(s, 0);
out_uint16_be(s, 0x1234);
out_uint8(s, 0);
/* rdpNegData */
if (self->rdpNegData)
{
if (self->failureCode)
{
out_uint8(s, RDP_NEG_FAILURE);
out_uint8(s, 0); /* no flags */
out_uint16_le(s, 8); /* must be 8 */
out_uint32_le(s, self->failureCode); /* failure code */
}
else
{
out_uint8(s, RDP_NEG_RSP);
//TODO: hardcoded flags
out_uint8(s, EXTENDED_CLIENT_DATA_SUPPORTED); /* flags */
out_uint16_le(s, 8); /* must be 8 */
out_uint32_le(s, self->selectedProtocol); /* selected protocol */
}
}
s_mark_end(s);
len = (int) (s->end - holdp);
len_indicator = (int) (s->end - len_indicator_ptr) - 1;
len_ptr[0] = len >> 8;
len_ptr[1] = len;
len_indicator_ptr[0] = len_indicator;
if (trans_write_copy_s(self->trans, s) != 0)
{
free_stream(s);
return 1;
}
free_stream(s);
return 0;
}
/*****************************************************************************/
/* returns error */
int APP_CC
xrdp_iso_incoming(struct xrdp_iso *self)
{
int rv = 0;
int code;
int len;
int cookie_index;
int cc_type;
char text[256];
char *pend;
struct stream *s;
LLOGLN(10, (" in xrdp_iso_incoming"));
s = libxrdp_force_read(self->trans);
if (s == 0)
{
return 1;
}
if (xrdp_iso_recv_msg(self, s, &code, &len) != 0)
{
LLOGLN(0, ("xrdp_iso_incoming: xrdp_iso_recv_msg returned non zero"));
return 1;
}
if ((code != ISO_PDU_CR) || (len < 6))
{
return 1;
}
/* process connection request */
pend = s->p + (len - 6);
cookie_index = 0;
while (s->p < pend)
{
in_uint8(s, cc_type);
switch (cc_type)
{
default:
break;
case RDP_NEG_REQ: /* rdpNegReq 1 */
self->rdpNegData = 1;
if (xrdp_iso_process_rdp_neg_req(self, s) != 0)
{
LLOGLN(0, ("xrdp_iso_incoming: xrdp_iso_process_rdpNegReq returned non zero"));
return 1;
}
break;
case RDP_CORRELATION_INFO: /* rdpCorrelationInfo 6 */
// TODO
in_uint8s(s, 1 + 2 + 16 + 16);
break;
case 'C': /* Cookie routingToken */
while (s->p < pend)
{
text[cookie_index] = cc_type;
cookie_index++;
if (cookie_index > 255)
{
cookie_index = 255;
}
if ((s->p[0] == 0x0D) && (s->p[1] == 0x0A))
{
in_uint8s(s, 2);
text[cookie_index] = 0;
cookie_index = 0;
if (g_strlen(text) > 0)
{
}
break;
}
in_uint8(s, cc_type);
}
break;
}
}
/* negotiate client-server security layer */
rv = xrdp_iso_negotiate_security(self);
/* send connection confirm back to client */
if (xrdp_iso_send_cc(self) != 0)
{
LLOGLN(0, ("xrdp_iso_incoming: xrdp_iso_send_cc returned non zero"));
return 1;
}
LLOGLN(10, (" out xrdp_iso_incoming"));
return rv;
}
/*****************************************************************************/
/* returns error */
int APP_CC
xrdp_iso_init(struct xrdp_iso *self, struct stream *s)
{
init_stream(s, 8192 * 4); /* 32 KB */
s_push_layer(s, iso_hdr, 7);
return 0;
}
/*****************************************************************************/
/* returns error */
int APP_CC
xrdp_iso_send(struct xrdp_iso *self, struct stream *s)
{
int len;
LLOGLN(10, (" in xrdp_iso_send"));
s_pop_layer(s, iso_hdr);
len = (int) (s->end - s->p);
out_uint8(s, 3);
out_uint8(s, 0);
out_uint16_be(s, len);
out_uint8(s, 2);
out_uint8(s, ISO_PDU_DT);
out_uint8(s, 0x80);
if (trans_write_copy_s(self->trans, s) != 0)
{
return 1;
}
LLOGLN(10, (" out xrdp_iso_send"));
return 0;
}