diff options
Diffstat (limited to 'libxrdp/xrdp_sec.c')
| -rw-r--r-- | libxrdp/xrdp_sec.c | 232 |
1 files changed, 216 insertions, 16 deletions
diff --git a/libxrdp/xrdp_sec.c b/libxrdp/xrdp_sec.c index 726fcde4..161f88f8 100644 --- a/libxrdp/xrdp_sec.c +++ b/libxrdp/xrdp_sec.c @@ -138,7 +138,7 @@ hex_str_to_bin(char *in, char *out, int out_len) /*****************************************************************************/ struct xrdp_sec *APP_CC xrdp_sec_create(struct xrdp_rdp *owner, struct trans *trans, int crypt_level, - int channel_code) + int channel_code, int multimon) { struct xrdp_sec *self; @@ -168,6 +168,7 @@ xrdp_sec_create(struct xrdp_rdp *owner, struct trans *trans, int crypt_level, } self->channel_code = channel_code; + self->multimon = multimon; if (self->decrypt_rc4_info != NULL) { @@ -331,12 +332,20 @@ unicode_in(struct stream *s, int uni_len, char *dst, int dst_len) break; } + if (!s_check_rem(s, 2)) + { + return 1; + } in_uint8(s, dst[dst_index]); in_uint8s(s, 1); dst_index++; src_index += 2; } + if (!s_check_rem(s, 2)) + { + return 1; + } in_uint8s(s, 2); return 0; } @@ -359,6 +368,10 @@ xrdp_sec_process_logon_info(struct xrdp_sec *self, struct stream *s) /* initialize (zero out) local variables */ g_memset(tmpdata, 0, sizeof(char) * 256); + if (!s_check_rem(s, 8)) + { + return 1; + } in_uint8s(s, 4); in_uint32_le(s, flags); DEBUG(("in xrdp_sec_process_logon_info flags $%x", flags)); @@ -398,6 +411,10 @@ xrdp_sec_process_logon_info(struct xrdp_sec *self, struct stream *s) } } + if (!s_check_rem(s, 2)) + { + return 1; + } in_uint16_le(s, len_domain); if (len_domain > 511) @@ -406,6 +423,10 @@ xrdp_sec_process_logon_info(struct xrdp_sec *self, struct stream *s) return 1; } + if (!s_check_rem(s, 2)) + { + return 1; + } in_uint16_le(s, len_user); if (len_user > 511) @@ -414,6 +435,10 @@ xrdp_sec_process_logon_info(struct xrdp_sec *self, struct stream *s) return 1; } + if (!s_check_rem(s, 2)) + { + return 1; + } in_uint16_le(s, len_password); if (len_password > 511) @@ -422,6 +447,10 @@ xrdp_sec_process_logon_info(struct xrdp_sec *self, struct stream *s) return 1; } + if (!s_check_rem(s, 2)) + { + return 1; + } in_uint16_le(s, len_program); if (len_program > 511) @@ -430,6 +459,10 @@ xrdp_sec_process_logon_info(struct xrdp_sec *self, struct stream *s) return 1; } + if (!s_check_rem(s, 2)) + { + return 1; + } in_uint16_le(s, len_directory); if (len_directory > 511) @@ -438,35 +471,75 @@ xrdp_sec_process_logon_info(struct xrdp_sec *self, struct stream *s) return 1; } - unicode_in(s, len_domain, self->rdp_layer->client_info.domain, 255); + if (unicode_in(s, len_domain, self->rdp_layer->client_info.domain, 255) != 0) + { + return 1; + } DEBUG(("domain %s", self->rdp_layer->client_info.domain)); - unicode_in(s, len_user, self->rdp_layer->client_info.username, 255); + if (unicode_in(s, len_user, self->rdp_layer->client_info.username, 255) != 0) + { + return 1; + } DEBUG(("username %s", self->rdp_layer->client_info.username)); if (flags & RDP_LOGON_AUTO) { - unicode_in(s, len_password, self->rdp_layer->client_info.password, 255); + if (unicode_in(s, len_password, self->rdp_layer->client_info.password, 255) != 0) + { + return 1; + } DEBUG(("flag RDP_LOGON_AUTO found")); } else { + if (!s_check_rem(s, len_password + 2)) + { + return 1; + } in_uint8s(s, len_password + 2); if (self->rdp_layer->client_info.require_credentials) + { + g_writeln("xrdp_sec_process_logon_info: credentials on cmd line is mandatory"); return 1; /* credentials on cmd line is mandatory */ + } } - unicode_in(s, len_program, self->rdp_layer->client_info.program, 255); + if (unicode_in(s, len_program, self->rdp_layer->client_info.program, 255) != 0) + { + return 1; + } DEBUG(("program %s", self->rdp_layer->client_info.program)); - unicode_in(s, len_directory, self->rdp_layer->client_info.directory, 255); + if (unicode_in(s, len_directory, self->rdp_layer->client_info.directory, 255) != 0) + { + return 1; + } DEBUG(("directory %s", self->rdp_layer->client_info.directory)); if (flags & RDP_LOGON_BLOB) { + if (!s_check_rem(s, 4)) + { + return 1; + } in_uint8s(s, 2); /* unknown */ in_uint16_le(s, len_ip); - unicode_in(s, len_ip - 2, tmpdata, 255); + if (unicode_in(s, len_ip - 2, tmpdata, 255) != 0) + { + return 1; + } + if (!s_check_rem(s, 2)) + { + return 1; + } in_uint16_le(s, len_dll); - unicode_in(s, len_dll - 2, tmpdata, 255); + if (unicode_in(s, len_dll - 2, tmpdata, 255) != 0) + { + return 1; + } + if (!s_check_rem(s, 4 + 62 + 22 + 62 + 26 + 4)) + { + return 1; + } in_uint32_le(s, tzone); /* len of timetone */ in_uint8s(s, 62); /* skip */ in_uint8s(s, 22); /* skip misc. */ @@ -676,17 +749,29 @@ xrdp_sec_recv(struct xrdp_sec *self, struct stream *s, int *chan) return 1; } + if (!s_check_rem(s, 4)) + { + return 1; + } in_uint32_le(s, flags); DEBUG((" in xrdp_sec_recv flags $%x", flags)); if (flags & SEC_ENCRYPT) /* 0x08 */ { + if (!s_check_rem(s, 8)) + { + return 1; + } in_uint8s(s, 8); /* signature */ xrdp_sec_decrypt(self, s->p, (int)(s->end - s->p)); } if (flags & SEC_CLIENT_RANDOM) /* 0x01 */ { + if (!s_check_rem(s, 4 + 64)) + { + return 1; + } in_uint32_le(s, len); in_uint8a(s, self->client_crypt_random, 64); xrdp_sec_rsa_op(self->client_random, self->client_crypt_random, @@ -836,23 +921,88 @@ xrdp_sec_process_mcs_data_channels(struct xrdp_sec *self, struct stream *s) return 0; } + if (!s_check_rem(s, 4)) + { + return 1; + } + in_uint32_le(s, num_channels); + if (num_channels > 31) + { + return 1; + } + for (index = 0; index < num_channels; index++) { channel_item = (struct mcs_channel_item *) g_malloc(sizeof(struct mcs_channel_item), 1); + if (!s_check_rem(s, 12)) + { + return 1; + } in_uint8a(s, channel_item->name, 8); in_uint32_le(s, channel_item->flags); channel_item->chanid = MCS_GLOBAL_CHANNEL + (index + 1); - list_add_item(self->mcs_layer->channel_list, (long)channel_item); + list_add_item(self->mcs_layer->channel_list, (tintptr)channel_item); DEBUG(("got channel flags %8.8x name %s", channel_item->flags, channel_item->name)); } return 0; } +/*****************************************************************************/ +/* reads the client monitors data */ +static int APP_CC +xrdp_sec_process_mcs_data_monitors(struct xrdp_sec *self, struct stream *s) +{ + int index; + int monitorCount; + int flags; + struct mcs_monitor_item *monitor_item; + DEBUG(("processing monitors data, allow_multimon is %d", self->multimon)); + /* this is an option set in xrdp.ini */ + if (self->multimon != 1) /* are multi-monitors allowed ? */ + { + DEBUG(("[INFO] xrdp_sec_process_mcs_data_monitors: multimon is not " + "allowed, skipping")); + return 0; + } + in_uint32_le(s, flags); /* flags */ + //verify flags - must be 0x0 + if (flags != 0) + { + DEBUG(("[ERROR] xrdp_sec_process_mcs_data_monitors: flags MUST be " + "zero, detected: %d", flags)); + return 0; + } + in_uint32_le(s, monitorCount); + //verify monitorCount - max 16 + if (monitorCount > 16) + { + DEBUG(("[ERROR] xrdp_sec_process_mcs_data_monitors: max allowed " + "monitors is 16, detected: %d", monitorCount)); + return 0; + } + for (index = 0; index < monitorCount; index++) + { + monitor_item = (struct mcs_monitor_item *) + g_malloc(sizeof(struct mcs_monitor_item), 1); + in_uint32_le(s, monitor_item->left); + in_uint32_le(s, monitor_item->top); + in_uint32_le(s, monitor_item->right); + in_uint32_le(s, monitor_item->bottom); + in_uint32_le(s, monitor_item->is_primary); + list_add_item(self->mcs_layer->monitor_list, (long)monitor_item); + DEBUG(("got monitor: left: %d, top: %d, right: %d, bottom: %d, is " + "primary: %d", monitor_item->left, monitor_item->top, + monitor_item->right, monitor_item->bottom, + monitor_item->is_primary)); + } + + return 0; +} /*****************************************************************************/ /* process client mcs data, we need some things in here to create the server mcs data */ @@ -864,10 +1014,14 @@ xrdp_sec_process_mcs_data(struct xrdp_sec *self) int tag = 0; int size = 0; - s = &self->client_mcs_data; + s = &(self->client_mcs_data); /* set p to beginning */ s->p = s->data; /* skip header */ + if (!s_check_rem(s, 23)) + { + return 1; + } in_uint8s(s, 23); while (s_check_rem(s, 4)) @@ -890,10 +1044,16 @@ xrdp_sec_process_mcs_data(struct xrdp_sec *self) case SEC_TAG_CLI_CRYPT: break; case SEC_TAG_CLI_CHANNELS: - xrdp_sec_process_mcs_data_channels(self, s); + if (xrdp_sec_process_mcs_data_channels(self, s) != 0) + { + return 1; + } break; case SEC_TAG_CLI_4: break; + case SEC_TAG_CLI_MONITOR: + xrdp_sec_process_mcs_data_monitors(self, s); + break; default: g_writeln("error unknown xrdp_sec_process_mcs_data tag %d size %d", tag, size); @@ -940,13 +1100,32 @@ xrdp_sec_out_mcs_data(struct xrdp_sec *self) out_uint8(s, 0x63); /* c */ out_uint8(s, 0x44); /* D */ out_uint8(s, 0x6e); /* n */ - out_uint16_be(s, 0x80fc + (num_channels_even * 2)); + if (self->mcs_layer->iso_layer->selectedProtocol != -1) + { // Check for RDPNEGDATA availability + out_uint16_be(s, 0x80fc + (num_channels_even * 2) + 4); + } + else + { + out_uint16_be(s, 0x80fc + (num_channels_even * 2)); + } out_uint16_le(s, SEC_TAG_SRV_INFO); - out_uint16_le(s, 8); /* len */ + if (self->mcs_layer->iso_layer->selectedProtocol != -1) + { + out_uint16_le(s, 12); /* len */ + } + else + { + out_uint16_le(s, 8); /* len */ + } out_uint8(s, 4); /* 4 = rdp5 1 = rdp4 */ out_uint8(s, 0); out_uint8(s, 8); out_uint8(s, 0); + if (self->mcs_layer->iso_layer->selectedProtocol != -1) + { + /* clientReqeustedProtocol */ + out_uint32_le(s, self->mcs_layer->iso_layer->selectedProtocol); + } out_uint16_le(s, SEC_TAG_SRV_CHANNELS); out_uint16_le(s, 8 + (num_channels_even * 2)); /* len */ out_uint16_le(s, MCS_GLOBAL_CHANNEL); /* 1003, 0x03eb main channel */ @@ -999,7 +1178,7 @@ xrdp_sec_out_mcs_data(struct xrdp_sec *self) /*****************************************************************************/ /* process the mcs client data we received from the mcs layer */ -static void APP_CC +static int APP_CC xrdp_sec_in_mcs_data(struct xrdp_sec *self) { struct stream *s = (struct stream *)NULL; @@ -1011,6 +1190,10 @@ xrdp_sec_in_mcs_data(struct xrdp_sec *self) s = &(self->client_mcs_data); /* get hostname, its unicode */ s->p = s->data; + if (!s_check_rem(s, 47)) + { + return 1; + } in_uint8s(s, 47); g_memset(client_info->hostname, 0, 32); c = 1; @@ -1018,6 +1201,10 @@ xrdp_sec_in_mcs_data(struct xrdp_sec *self) while (index < 16 && c != 0) { + if (!s_check_rem(s, 2)) + { + return 1; + } in_uint8(s, c); in_uint8s(s, 1); client_info->hostname[index] = c; @@ -1026,13 +1213,22 @@ xrdp_sec_in_mcs_data(struct xrdp_sec *self) /* get build */ s->p = s->data; + if (!s_check_rem(s, 43 + 4)) + { + return 1; + } in_uint8s(s, 43); in_uint32_le(s, client_info->build); /* get keylayout */ s->p = s->data; + if (!s_check_rem(s, 39 + 4)) + { + return 1; + } in_uint8s(s, 39); in_uint32_le(s, client_info->keylayout); s->p = s->data; + return 0; } /*****************************************************************************/ @@ -1059,7 +1255,8 @@ xrdp_sec_incoming(struct xrdp_sec *self) if (file_by_name_read_section(key_file, "keys", items, values) != 0) { /* this is a show stopper */ - log_message(LOG_LEVEL_ALWAYS,"XRDP cannot read file: %s (check permissions)", key_file); + log_message(LOG_LEVEL_ALWAYS, "XRDP cannot read file: %s " + "(check permissions)", key_file); list_delete(items); list_delete(values); return 1; @@ -1105,7 +1302,10 @@ xrdp_sec_incoming(struct xrdp_sec *self) (int)(self->server_mcs_data.end - self->server_mcs_data.data)); #endif DEBUG((" out xrdp_sec_incoming")); - xrdp_sec_in_mcs_data(self); + if (xrdp_sec_in_mcs_data(self) != 0) + { + return 1; + } return 0; } |
