Compare commits

...

10 Commits

Author SHA1 Message Date
1fb029cde7 Initial push with a few changes 2024-05-31 15:27:02 +02:00
Bruno Moreira-Guedes
4716f1e016 Format changes in GH issue templates
Improved capitalization of template names
2021-12-30 05:23:18 -03:00
Bruno Moreira-Guedes
da36432c31 Asking for help template
A template to collect proper information about an issue requesting for help. It also suggests to the user to try reading the documentation first.
2021-12-30 05:20:26 -03:00
Bruno Moreira-Guedes
3986164464 Feature Suggestion Template
Added template to help the users to think deep about their feature requests
2021-12-30 05:10:26 -03:00
Bruno Moreira-Guedes
134262fc03 Bug report template
A template for an objective bug report with basic information and reproduction steps
2021-12-30 04:35:32 -03:00
wojciech.kepka
1620a263bf Fix typo in warning message in utils.c 2020-02-06 14:56:26 +01:00
Markus Beth
53ba87dc17 use correct modulus and exponent in rdssl_rkey_get_exp_mod 2019-12-02 11:22:13 +01:00
Pierre Ossman
50f607ee61 Update version to 1.9.0 2019-09-20 09:03:48 +02:00
Pierre Ossman
5ce283806c Restore leniance in certificate key usage violations
It was removed in 256d8e2 because the purpose was unclear. It turns
out that the automatically generated self signed certificates will
have Key Encipherment and Data Encipherment set as key usage, but
the required ones are Digital Signature and Key Encipherment. A
proper certificate generally doesn't have this issue, but connecting
to stand alone machines without a proper certificate is common.

Unfortunately the %COMPAT flag is the only thing that makes GnuTLS
tolerate this bug, but that flag also allows a lot of other protocol
violations.
2019-09-20 09:00:04 +02:00
Pierre Ossman
fdb2da450a Fix initial security handshake for old systems
The conversion from OpenSSL to GnuTLS (or GMP in this case) got
the endianness mixed up in the initial security handshake. It got
it wrong in two places though, which cancelled each other out when
X.509 certificates are used. But servers using the older system,
like Windows XP, would fail the handshake as different endianness
was then used when reading the RSA key and when using it.
2019-09-20 08:36:10 +02:00
13 changed files with 1013 additions and 1442 deletions

39
.github/ISSUE_TEMPLATE/bug-report.md vendored Normal file
View File

@ -0,0 +1,39 @@
---
name: Bug Report
about: Follow this template to report a bug
title: "[BUG] "
labels: ''
assignees: ''
---
PLEASE, FOLLOW AS CLOSELY AS POSSIBLE THE FOLLOWING SCRIPT TO FILL A BUG REPORT (and remove hints and instructions)
**Describe the bug**
A clear and concise description of what the bug is.
**Reproduction Steps**
Explain in detailed steps how to reproduce the bug
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Important Information:**
- rdesktop Version (*): [e.g. 1.9.0]
- Client OS (*): [e.g. Fedora Core 35]
- Server OS: [e.g. Windows 10]
- Server Software: [e.g. xrdp]
- Server Software Version: [e.g. 1.5.1]
**Checklist**
- [ ] This bug prevents me from using rdesktop
- [ ] This bug is a security issue
- [ ] This bug causes a bad experience with rdesktop
- [ ] I have supplied all possible sections of the bug report template
**Additional Information**
Add any relevant contextual information or other details about the problem here, like command line arguments, output, environment variables, gdb output, screenshots, etc.
HINT: the output is often useful, run `rdesktop` with the `-v` argument (verbose) to produce a more detailed output.

View File

@ -0,0 +1,29 @@
---
name: Feature Suggestion
about: Suggest a feature for rdesktop
title: "[FS]"
labels: ''
assignees: ''
---
PLEASE, TAKE THIS TEMPLATE AS A SCRIPT TO HELP YOU TO THINK AS CONCRETELY AS POSSIBLE ABOUT THE PROPOSED FEATURE THAT DON'T NEED TO BE STRICTLY FOLLOWED. (remove this message before posting)
**Brief Description**
Shortly describe the feature you are proposing (1-3 phrases).
**Needs or Improvements**
The user needs your feature suggestion are intended to satisfy and/or to satisfy in a better way (i.e. know when the connection is decreasing in quality).
**The proposed feature is**
- [ ] A feature to satisfy a new need that is not currently satisfied
- [ ] A feature to improve the way an already met need is satisfied
**Detailed Solution**
Describe how the proposed feature would work, how it would be used, etc
**Expected Interface**
Describe how the interface for this feature would be (i.e. a `-f FILENAME` argument to the command line).
**Requirements**
Optionally, add a list of specific requirements for this feature

17
.github/ISSUE_TEMPLATE/getting-help.md vendored Normal file
View File

@ -0,0 +1,17 @@
---
name: Getting Help
about: Get help with some usage related problem
title: "[SUP]"
labels: ''
assignees: ''
---
**What do you need help with?**
Describe what you would like to achieve with rdesktop
**Have you tried anything so far?**
If you tried to do it in some way and it didn't work, please describe how you tried to do and what went wrong (i.e. an error message)
**Have you tried the docs?**
- [ ] Yes, I have tried to read the appropriate docs but haven't found a solution

480
asn.c
View File

@ -30,314 +30,286 @@
static asn1_node *asn_defs = NULL;
#define MAX_ERROR_DESCRIPTION_SIZE 1024
char errstr[MAX_ERROR_DESCRIPTION_SIZE];
#define MAX_ERROR_DESCRIPTION_SIZE 1024
static char errstr[MAX_ERROR_DESCRIPTION_SIZE];
/* Parse an ASN.1 BER header */
RD_BOOL
ber_parse_header(STREAM s, int tagval, uint32 *length)
static int ber_parse_header(STREAM s, int tagval, uint32 *length)
{
int tag, len;
int tag, len;
if (tagval > 0xff)
{
if (!s_check_rem(s, 2)) {
return False;
}
in_uint16_be(s, tag);
}
else
{
if (!s_check_rem(s, 1)) {
return False;
}
in_uint8(s, tag);
}
if (tagval > 0xff) {
if (!s_check_rem(s, 2)) {
return ASN_PARSE_ERROR;
}
in_uint16_be(s, tag);
} else {
if (!s_check_rem(s, 1)) {
return ASN_PARSE_ERROR;
}
in_uint8(s, tag);
}
if (tag != tagval)
{
logger(Core, Error, "ber_parse_header(), expected tag %d, got %d", tagval, tag);
return False;
}
if (tag != tagval) {
logger(Core, Error, "ber_parse_header(), expected tag %d, got %d", tagval, tag);
return ASN_TAG_ERROR;
}
if (!s_check_rem(s, 1)) {
return False;
}
in_uint8(s, len);
if (!s_check_rem(s, 1)) {
return ASN_PARSE_ERROR;
}
in_uint8(s, len);
if (len & 0x80)
{
len &= ~0x80;
if (!s_check_rem(s, len)) {
return False;
}
*length = 0;
while (len--)
next_be(s, *length);
}
else
*length = len;
if (len & 0x80) {
len &= ~0x80;
if (!s_check_rem(s, len)) {
return ASN_PARSE_ERROR;
}
*length = 0;
while (len--) {
next_be(s, *length);
}
} else {
*length = len;
}
return True;
return ASN_SUCCESS;
}
void
ber_out_sequence(STREAM out, STREAM content)
static void ber_out_sequence(STREAM out, STREAM content)
{
size_t length;
length = (content ? s_length(content) : 0);
ber_out_header(out, BER_TAG_SEQUENCE | BER_TAG_CONSTRUCTED, length);
if (content)
out_stream(out, content);
size_t length;
length = (content ? s_length(content) : 0);
ber_out_header(out, BER_TAG_SEQUENCE | BER_TAG_CONSTRUCTED, length);
if (content) {
out_stream(out, content);
}
}
/* Output an ASN.1 BER header */
void
ber_out_header(STREAM s, int tagval, int length)
static void ber_out_header(STREAM s, int tagval, int length)
{
if (tagval > 0xff)
{
out_uint16_be(s, tagval);
}
else
{
out_uint8(s, tagval);
}
if (tagval > 0xff) {
out_uint16_be(s, tagval);
} else {
out_uint8(s, tagval);
}
if (length >= 0x80)
{
out_uint8(s, 0x82);
out_uint16_be(s, length);
}
else
out_uint8(s, length);
if (length >= 0x80) {
out_uint8(s, 0x82);
out_uint16_be(s, length);
} else {
out_uint8(s, length);
}
}
/* Output an ASN.1 BER integer */
void
ber_out_integer(STREAM s, int value)
static void ber_out_integer(STREAM s, int value)
{
ber_out_header(s, BER_TAG_INTEGER, 2);
out_uint16_be(s, value);
ber_out_header(s, BER_TAG_INTEGER, 2);
out_uint16_be(s, value);
}
RD_BOOL
ber_in_header(STREAM s, int *tagval, int *decoded_len)
static int ber_in_header(STREAM s, int *tagval, int *decoded_len)
{
in_uint8(s, *tagval);
in_uint8(s, *decoded_len);
in_uint8(s, *tagval);
in_uint8(s, *decoded_len);
if (*decoded_len < 0x80)
return True;
else if (*decoded_len == 0x81)
{
in_uint8(s, *decoded_len);
return True;
}
else if (*decoded_len == 0x82)
{
in_uint16_be(s, *decoded_len);
return True;
}
if (*decoded_len < 0x80) {
return ASN_SUCCESS;
} else if (*decoded_len == 0x81) {
in_uint8(s, *decoded_len);
return ASN_SUCCESS;
} else if (*decoded_len == 0x82) {
in_uint16_be(s, *decoded_len);
return ASN_SUCCESS;
}
return False;
return ASN_PARSE_ERROR;
}
int init_asn1_lib(void)
static int init_asn1_lib(void)
{
int asn1_rv;
int asn1_rv;
if (asn_defs) {
return 0;
}
if (asn_defs) {
return ASN_SUCCESS;
}
asn_defs = malloc(sizeof(*asn_defs));
asn_defs = malloc(sizeof(*asn_defs));
if (!asn_defs) {
logger(Core, Error, "%s:%s:%d Failed to allocate memory for ASN.1 parser\n",
__FILE__, __func__, __LINE__);
return 1;
}
if (!asn_defs) {
logger(Core, Error, "%s:%s:%d Failed to allocate memory for ASN.1 parser\n",
__FILE__, __func__, __LINE__);
return ASN_MEM_ERROR;
}
*asn_defs = NULL;
*asn_defs = NULL;
if (ASN1_SUCCESS != (asn1_rv = asn1_array2tree(pkix_asn1_tab, asn_defs, errstr))) {
logger(Core, Error, "%s:%s:%d Failed to init ASN.1 parser. Error = 0x%x (%s)\n",
__FILE__, __func__, __LINE__, asn1_rv, asn1_strerror(asn1_rv));
if (ASN1_SUCCESS != (asn1_rv = asn1_array2tree(pkix_asn1_tab, asn_defs, errstr))) {
logger(Core, Error, "%s:%s:%d Failed to init ASN.1 parser. Error = 0x%x (%s)\n",
__FILE__, __func__, __LINE__, asn1_rv, asn1_strerror(asn1_rv));
return 1;
}
free(asn_defs);
asn_defs = NULL;
return asn1_rv;
}
return 0;
return ASN_SUCCESS;
}
/* Encode RSA public key into DER PKCS#1 */
/* Returns; 0 - success, 1 - fatal error, 2 - insufficient space in buffer */
int write_pkcs1_der_pubkey(const gnutls_datum_t *m, const gnutls_datum_t *e, uint8_t *out, int *out_len)
static int write_pkcs1_der_pubkey(const gnutls_datum_t *m, const gnutls_datum_t *e, uint8_t *out, int *out_len)
{
int asn1_rv;
asn1_node asn_cert;
int asn1_rv;
asn1_node asn_cert;
if (!asn_defs) {
if (init_asn1_lib() != 0) {
return 1;
}
}
if (!asn_defs) {
if (init_asn1_lib() != ASN_SUCCESS) {
return ASN_INIT_ERROR;
}
}
if (ASN1_SUCCESS != (asn1_rv = asn1_create_element(*asn_defs, "PKIX1Implicit88.RSAPublicKey", &asn_cert))) {
logger(Core, Error, "%s:%s:%d Failed to create ASN.1 parser element for RSAPublicKey. Error = 0x%x (%s)\n",
__FILE__, __func__, __LINE__, asn1_rv, asn1_strerror(asn1_rv));
return 1;
}
if (ASN1_SUCCESS != (asn1_rv = asn1_create_element(*asn_defs, "PKIX1Implicit88.RSAPublicKey", &asn_cert))) {
logger(Core, Error, "%s:%s:%d Failed to create ASN.1 parser element for RSAPublicKey. Error = 0x%x (%s)\n",
__FILE__, __func__, __LINE__, asn1_rv, asn1_strerror(asn1_rv));
return ASN_CREATE_ERROR;
}
if (ASN1_SUCCESS != (asn1_rv = asn1_write_value(asn_cert, "modulus", m->data, m->size))) {
logger(Core, Error, "%s:%s:%d Failed to write modulus. Error = 0x%x (%s)\n",
__FILE__, __func__, __LINE__, asn1_rv, asn1_strerror(asn1_rv));
if (ASN1_SUCCESS != (asn1_rv = asn1_write_value(asn_cert, "modulus", m->data, m->size))) {
logger(Core, Error, "%s:%s:%d Failed to write modulus. Error = 0x%x (%s)\n",
__FILE__, __func__, __LINE__, asn1_rv, asn1_strerror(asn1_rv));
return 1;
}
return ASN_WRITE_ERROR;
}
if (ASN1_SUCCESS != (asn1_rv = asn1_write_value(asn_cert, "publicExponent", e->data, e->size))) {
logger(Core, Error, "%s:%s:%d Failed to write publicExponent. Error = 0x%x (%s)\n",
__FILE__, __func__, __LINE__, asn1_rv, asn1_strerror(asn1_rv));
return 1;
}
if (ASN1_SUCCESS != (asn1_rv = asn1_write_value(asn_cert, "publicExponent", e->data, e->size))) {
logger(Core, Error, "%s:%s:%d Failed to write publicExponent. Error = 0x%x (%s)\n",
__FILE__, __func__, __LINE__, asn1_rv, asn1_strerror(asn1_rv));
return ASN_WRITE_ERROR;
}
if (ASN1_SUCCESS != (asn1_rv = asn1_der_coding(asn_cert, "", out, out_len, errstr))) {
logger(Core, Error, "%s:%s:%d Failed to encode PKIX1Implicit88.RSAPublicKey. Error = 0x%x (%s)\n",
__FILE__, __func__, __LINE__, asn1_rv, asn1_strerror(asn1_rv));
if (ASN1_SUCCESS != (asn1_rv = asn1_der_coding(asn_cert, "", out, out_len, errstr))) {
logger(Core, Error, "%s:%s:%d Failed to encode PKIX1Implicit88.RSAPublicKey. Error = 0x%x (%s)\n",
__FILE__, __func__, __LINE__, asn1_rv, asn1_strerror(asn1_rv));
if (asn1_rv == ASN1_MEM_ERROR) {
return 2;
}
return ASN_ENCODE_ERROR;
}
return 1;
}
return ASN_SUCCESS;
}
return 0;
static int libtasn_read_cert_pk(uint8_t *data, size_t len, char *oid, size_t *oid_size, gnutls_datum_t *m, gnutls_datum_t *e)
{
int asn1_rv;
asn1_node asn_cert;
/* Parse DER encoded x.509 certificate */
if (!asn_defs) {
if (init_asn1_lib() != ASN_SUCCESS) {
return ASN_INIT_ERROR;
}
}
if (ASN1_SUCCESS != (asn1_rv = asn1_create_element(*asn_defs, "PKIX1Implicit88.Certificate", &asn_cert))) {
logger(Core, Error, "%s:%s:%d Failed to create ASN.1 parser element. Error = 0x%x (%s)\n",
__FILE__, __func__, __LINE__, asn1_rv, asn1_strerror(asn1_rv));
return ASN_CREATE_ERROR;
}
if (ASN1_SUCCESS != (asn1_rv = asn1_der_decoding(&asn_cert, data, len, errstr))) {
logger(Core, Error, "%s:%s:%d Failed to decode certificate object. Error = 0x%x (%s)\n",
__FILE__, __func__, __LINE__, asn1_rv, asn1_strerror(asn1_rv));
return ASN_DECODE_ERROR;
}
if (oid && oid_size) {
if (ASN1_SUCCESS != (asn1_rv = asn1_read_value(asn_cert, "tbsCertificate.subjectPublicKeyInfo.algorithm.algorithm",
oid, (int *)oid_size)))
{
logger(Core, Error, "%s:%s:%d Failed to get cert's public key algorithm. Error = 0x%x (%s)\n",
__FILE__, __func__, __LINE__, asn1_rv, asn1_strerror(asn1_rv));
return ASN_READ_ERROR;
}
}
if (m && e) {
int buflen;
uint8_t buf[16384];
asn1_node asn_key;
int nblen;
uint8_t newbuf[16384];
buflen = sizeof(buf) - 1;
if (ASN1_SUCCESS != (asn1_rv = asn1_read_value(asn_cert, "tbsCertificate.subjectPublicKeyInfo.subjectPublicKey", buf, &buflen))) {
logger(Core, Error, "%s:%s:%d Failed to get cert's public key. Error = 0x%x (%s)\n",
__FILE__, __func__, __LINE__, asn1_rv, asn1_strerror(asn1_rv));
return ASN_READ_ERROR;
}
if (ASN1_SUCCESS != (asn1_rv = asn1_create_element(*asn_defs, "PKIX1Implicit88.RSAPublicKey", &asn_key))) {
logger(Core, Error, "%s:%s:%d Failed to create ASN.1 parser element. Error = 0x%x (%s)\n",
__FILE__, __func__, __LINE__, asn1_rv, asn1_strerror(asn1_rv));
return ASN_CREATE_ERROR;
}
// As it' a BIT STRING the len constitutes the number of BITS, not BYTES
if (ASN1_SUCCESS != (asn1_rv = asn1_der_decoding(&asn_key, buf, buflen / 8, errstr))) {
logger(Core, Error, "%s:%s:%d Failed to decode public key object. Error = 0x%x (%s)\n",
__FILE__, __func__, __LINE__, asn1_rv, asn1_strerror(asn1_rv));
return ASN_DECODE_ERROR;
}
/* Get RSA public key's modulus and exponent */
nblen = sizeof(newbuf);
if (ASN1_SUCCESS != (asn1_rv = asn1_read_value(asn_key, "modulus", newbuf, &nblen))) {
logger(Core, Error, "%s:%s:%d Failed to get RSA public key's modulus. Error = 0x%x (%s)\n",
__FILE__, __func__, __LINE__, asn1_rv, asn1_strerror(asn1_rv));
return ASN_READ_ERROR;
}
m->size = nblen;
m->data = malloc(m->size);
if (!m->data) {
logger(Core, Error, "%s:%s:%d Failed to allocate memory for modulus.\n", __FILE__, __func__, __LINE__);
return ASN_MEM_ERROR;
}
memcpy((void *)m->data, newbuf, m->size);
nblen = sizeof(newbuf);
if (ASN1_SUCCESS != (asn1_rv = asn1_read_value(asn_key, "publicExponent", newbuf, &nblen))) {
logger(Core, Error, "%s:%s:%d Failed to get RSA public key's exponent. Error = 0x%x (%s)\n",
__FILE__, __func__, __LINE__, asn1_rv, asn1_strerror(asn1_rv));
free(m->data);
return ASN_READ_ERROR;
}
e->size = nblen;
e->data = malloc(e->size);
if (!e->data) {
logger(Core, Error, "%s:%s:%d Failed to allocate memory for exponent.\n", __FILE__, __func__, __LINE__);
free(m->data);
return ASN_MEM_ERROR;
}
memcpy((void *)e->data, newbuf, e->size);
}
return ASN_SUCCESS;
}
int libtasn_read_cert_pk_oid(uint8_t *data, size_t len, char *oid, size_t *oid_size)
{
int asn1_rv;
asn1_node asn_cert;
/* Parse DER encoded x.509 certificate */
if (!asn_defs) {
if (init_asn1_lib() != 0) {
return 1;
}
}
if (ASN1_SUCCESS != (asn1_rv = asn1_create_element(*asn_defs, "PKIX1Implicit88.Certificate", &asn_cert))) {
logger(Core, Error, "%s:%s:%d Failed to create ASN.1 parser element. Error = 0x%x (%s)\n",
__FILE__, __func__, __LINE__, asn1_rv, asn1_strerror(asn1_rv));
return 1;
}
if (ASN1_SUCCESS != (asn1_rv = asn1_der_decoding(&asn_cert, data, len, errstr))) {
logger(Core, Error, "%s:%s:%d Failed to decode certificate object. Error = 0x%x (%s)\n",
__FILE__, __func__, __LINE__, asn1_rv, asn1_strerror(asn1_rv));
return 1;
}
if (ASN1_SUCCESS != (asn1_rv = asn1_read_value(asn_cert, "tbsCertificate.subjectPublicKeyInfo.algorithm.algorithm",
oid, (int *)oid_size)))
{
logger(Core, Error, "%s:%s:%d Failed to get cert's public key algorithm. Error = 0x%x (%s)\n",
__FILE__, __func__, __LINE__, asn1_rv, asn1_strerror(asn1_rv));
return 1;
}
return 0;
return libtasn_read_cert_pk(data, len, oid, oid_size, NULL, NULL);
}
int libtasn_read_cert_pk_parameters(uint8_t *data, size_t len, gnutls_datum_t *m, gnutls_datum_t *e)
{
int asn1_rv;
asn1_node asn_cert;
int buflen;
uint8_t buf[16384];
asn1_node asn_key;
int nblen;
uint8_t newbuf[16384];
/* Parse DER encoded x.509 certificate */
init_asn1_lib();
if (ASN1_SUCCESS != (asn1_rv = asn1_create_element(*asn_defs, "PKIX1Implicit88.Certificate", &asn_cert))) {
logger(Core, Error, "%s:%s:%d Failed to create ASN.1 parser element. Error = 0x%x (%s)\n",
__FILE__, __func__, __LINE__, asn1_rv, asn1_strerror(asn1_rv));
return 1;
}
if (ASN1_SUCCESS != (asn1_rv = asn1_der_decoding(&asn_cert, data, len, errstr))) {
logger(Core, Error, "%s:%s:%d Failed to decode certificate object. Error = 0x%x (%s)\n",
__FILE__, __func__, __LINE__, asn1_rv, asn1_strerror(asn1_rv));
return 1;
}
buflen = sizeof(buf) - 1;
if (ASN1_SUCCESS != (asn1_rv = asn1_read_value(asn_cert, "tbsCertificate.subjectPublicKeyInfo.subjectPublicKey", buf, &buflen))) {
logger(Core, Error, "%s:%s:%d Failed to get cert's public key. Error = 0x%x (%s)\n",
__FILE__, __func__, __LINE__, asn1_rv, asn1_strerror(asn1_rv));
return 1;
}
if (ASN1_SUCCESS != (asn1_rv = asn1_create_element(*asn_defs, "PKIX1Implicit88.RSAPublicKey", &asn_key))) {
logger(Core, Error, "%s:%s:%d Failed to create ASN.1 parser element. Error = 0x%x (%s)\n",
__FILE__, __func__, __LINE__, asn1_rv, asn1_strerror(asn1_rv));
return 1;
}
// As it' a BIT STRING the len constitutes the number of BITS, not BYTES
if (ASN1_SUCCESS != (asn1_rv = asn1_der_decoding(&asn_key, buf, buflen / 8, errstr))) {
logger(Core, Error, "%s:%s:%d Failed to decode public key object. Error = 0x%x (%s)\n",
__FILE__, __func__, __LINE__, asn1_rv, asn1_strerror(asn1_rv));
return 1;
}
/* Get RSA public key's modulus and exponent */
nblen = sizeof(newbuf);
if (ASN1_SUCCESS != (asn1_rv = asn1_read_value(asn_key, "modulus", newbuf, &nblen))) {
logger(Core, Error, "%s:%s:%d Failed to get RSA public key's modulus. Error = 0x%x (%s)\n",
__FILE__, __func__, __LINE__, asn1_rv, asn1_strerror(asn1_rv));
return 1;
}
m->size = nblen;
if (!(m->data = malloc(m->size))) {
logger(Core, Error, "%s:%s:%d Failed to allocate memory for modulus.\n", __FILE__, __func__, __LINE__);
return 1;
}
memcpy((void *)m->data, newbuf, m->size);
nblen = sizeof(newbuf);
if (ASN1_SUCCESS != (asn1_rv = asn1_read_value(asn_key, "publicExponent", newbuf, &nblen))) {
logger(Core, Error, "%s:%s:%d Failed to get RSA public key's exponent. Error = 0x%x (%s)\n",
__FILE__, __func__, __LINE__, asn1_rv, asn1_strerror(asn1_rv));
return 1;
}
e->size = nblen;
if (!(e->data = malloc(e->size))) {
logger(Core, Error, "%s:%s:%d Failed to allocate memory for exponent.\n", __FILE__, __func__, __LINE__);
if (m->data) {
free(m->data);
}
return 1;
}
memcpy((void *)e->data, newbuf, e->size);
return 0;
return libtasn_read_cert_pk(data, len, NULL, NULL, m, e);
}

69
asn.h
View File

@ -16,8 +16,8 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _RDASN_H
#define _RDASN_H
#ifndef RDASN_H
#define RDASN_H
#include <gnutls/gnutls.h>
#include <libtasn1.h>
@ -29,17 +29,68 @@
extern "C" {
#endif
#define OID_SHA_WITH_RSA_SIGNATURE "1.3.14.3.2.15"
#define OID_MD5_WITH_RSA_SIGNATURE "1.3.14.3.2.25"
#define OID_SHA_WITH_RSA_SIGNATURE "1.3.14.3.2.15"
#define OID_MD5_WITH_RSA_SIGNATURE "1.3.14.3.2.25"
int init_asn1_lib(void);
int write_pkcs1_der_pubkey(const gnutls_datum_t *m, const gnutls_datum_t *e, uint8_t *out, int *out_len);
/**
* Initialize the ASN.1 library.
*
* This function initializes the ASN.1 library and should be called before any other ASN.1 functions.
*
* Returns: 0 on success, or a non-zero error code on failure.
*/
extern int init_asn1_lib(void);
int libtasn_read_cert_pk_oid(uint8_t *data, size_t len, char *oid, size_t *oid_size);
int libtasn_read_cert_pk_parameters(uint8_t *data, size_t len, gnutls_datum_t *m, gnutls_datum_t *e);
/**
* Encode an RSA public key into DER PKCS#1 format.
*
* This function encodes an RSA public key into DER PKCS#1 format. The modulus and exponent of the public key are
* provided as input, and the encoded key is returned in the output buffer.
*
* Parameters:
* - m: A pointer to a gnutls_datum_t structure that contains the modulus of the public key.
* - e: A pointer to a gnutls_datum_t structure that contains the exponent of the public key.
* - out: A pointer to the output buffer where the encoded key will be stored.
* - out_len: A pointer to an integer that will be set to the length of the encoded key.
*
* Returns: 0 on success, or a non-zero error code on failure.
*/
extern int write_pkcs1_der_pubkey(const gnutls_datum_t *m, const gnutls_datum_t *e, uint8_t *out, int *out_len);
/**
* Read the public key algorithm OID from a DER encoded x.509 certificate.
*
* This function reads the public key algorithm OID from a DER encoded x.509 certificate. The certificate is provided
* as input, and the OID is returned in the output buffer.
*
* Parameters:
* - data: A pointer to the input buffer that contains the DER encoded x.509 certificate.
* - len: The length of the input buffer.
* - oid: A pointer to the output buffer where the OID will be stored.
* - oid_size: A pointer to an integer that will be set to the length of the OID.
*
* Returns: 0 on success, or a non-zero error code on failure.
*/
extern int libtasn_read_cert_pk_oid(uint8_t *data, size_t len, char *oid, size_t *oid_size);
/**
* Read the public key parameters from a DER encoded x.509 certificate.
*
* This function reads the public key parameters (modulus and exponent) from a DER encoded x.509 certificate. The
* certificate is provided as input, and the parameters are returned in the output buffers.
*
* Parameters:
* - data: A pointer to the input buffer that contains the DER encoded x.509 certificate.
* - len: The length of the input buffer.
* - m: A pointer to a gnutls_datum_t structure that will be set to the modulus of the public key.
* - e: A pointer to a gnutls_datum_t structure that will be set to the exponent of the public key.
*
* Returns: 0 on success, or a non-zero error code on failure.
*/
extern int libtasn_read_cert_pk_parameters(uint8_t *data, size_t len, gnutls_datum_t *m, gnutls_datum_t *e);
#ifdef __cplusplus
}
#endif
#endif /* _RDASN_H */
#endif /* RDASN_H */

1195
bitmap.c

File diff suppressed because it is too large Load Diff

577
cache.c
View File

@ -20,6 +20,9 @@
*/
#include "rdesktop.h"
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
/* BITMAP CACHE */
extern int g_pstcache_fd[];
@ -30,22 +33,15 @@ extern int g_pstcache_fd[];
#define NOT_SET -1
#define IS_SET(idx) (idx >= 0)
/*
* TODO: Test for optimal value of BUMP_COUNT. TO_TOP gives lowest CPU utilisation but using
* a positive value will hopefully result in less frequently used bitmaps having a greater chance
* of being evicted from the cache, and thereby reducing the need to load bitmaps from disk.
* (Jeroen)
*/
#define BUMP_COUNT 40
struct bmpcache_entry
{
RD_HBITMAP bitmap;
sint16 previous;
sint16 next;
};
typedef struct bmpcache_entry {
RD_HBITMAP bitmap;
int16_t previous;
int16_t next;
} bmpcache_entry_t;
static struct bmpcache_entry g_bmpcache[3][0xa00];
static bmpcache_entry_t g_bmpcache[3][0xa00];
static RD_HBITMAP g_volatile_bc[3];
static int g_bmpcache_lru[3] = { NOT_SET, NOT_SET, NOT_SET };
@ -54,386 +50,310 @@ static int g_bmpcache_mru[3] = { NOT_SET, NOT_SET, NOT_SET };
static int g_bmpcache_count[3];
/* Setup the bitmap cache lru/mru linked list */
void
cache_rebuild_bmpcache_linked_list(uint8 id, sint16 * idx, int count)
{
int n = count, c = 0;
sint16 n_idx;
void cache_rebuild_bmpcache_linked_list(uint8_t id, int16_t *idx, int count) {
int n = count, c = 0;
int16_t n_idx;
/* find top, skip evicted bitmaps */
while (--n >= 0 && g_bmpcache[id][idx[n]].bitmap == NULL);
if (n < 0)
{
g_bmpcache_mru[id] = g_bmpcache_lru[id] = NOT_SET;
return;
}
/* find top, skip evicted bitmaps */
while (--n >= 0 && g_bmpcache[id][idx[n]].bitmap == NULL);
if (n < 0) {
g_bmpcache_mru[id] = g_bmpcache_lru[id] = NOT_SET;
return;
}
g_bmpcache_mru[id] = idx[n];
g_bmpcache[id][idx[n]].next = NOT_SET;
n_idx = idx[n];
c++;
g_bmpcache_mru[id] = idx[n];
g_bmpcache[id][idx[n]].next = NOT_SET;
n_idx = idx[n];
c++;
/* link list */
while (n >= 0)
{
/* skip evicted bitmaps */
while (--n >= 0 && g_bmpcache[id][idx[n]].bitmap == NULL);
/* link list */
while (n >= 0) {
/* skip evicted bitmaps */
while (--n >= 0 && g_bmpcache[id][idx[n]].bitmap == NULL);
if (n < 0)
break;
if (n < 0)
break;
g_bmpcache[id][n_idx].previous = idx[n];
g_bmpcache[id][idx[n]].next = n_idx;
n_idx = idx[n];
c++;
}
g_bmpcache[id][n_idx].previous = idx[n];
g_bmpcache[id][idx[n]].next = n_idx;
n_idx = idx[n];
c++;
}
g_bmpcache[id][n_idx].previous = NOT_SET;
g_bmpcache_lru[id] = n_idx;
g_bmpcache[id][n_idx].previous = NOT_SET;
g_bmpcache_lru[id] = n_idx;
if (c != g_bmpcache_count[id])
{
logger(Core, Error,
"cache_rebuild_bmpcache_linked_list(), %d in bitmap cache linked list, %d in ui cache...",
c, g_bmpcache_count[id]);
exit(EX_SOFTWARE);
}
if (c != g_bmpcache_count[id]) {
logger(Core, Error,
"cache_rebuild_bmpcache_linked_list(), %d in bitmap cache linked list, %d in ui cache...",
c, g_bmpcache_count[id]);
exit(EXIT_FAILURE);
}
}
/* Move a bitmap to a new position in the linked list. */
void
cache_bump_bitmap(uint8 id, uint16 idx, int bump)
{
int p_idx, n_idx, n;
void cache_bump_bitmap(uint8_t id, uint16_t idx, int bump) {
int p_idx, n_idx, n;
if (!IS_PERSISTENT(id))
return;
if (!IS_PERSISTENT(id))
return;
if (g_bmpcache_mru[id] == idx)
return;
if (g_bmpcache_mru[id] == idx)
return;
logger(Core, Debug, "cache_bump_bitmap(), id=%d, idx=%d, bump=%d", id, idx, bump);
logger(Core, Debug, "cache_bump_bitmap(), id=%d, idx=%d, bump=%d", id, idx, bump);
n_idx = g_bmpcache[id][idx].next;
p_idx = g_bmpcache[id][idx].previous;
n_idx = g_bmpcache[id][idx].next;
p_idx = g_bmpcache[id][idx].previous;
if (IS_SET(n_idx))
{
/* remove */
--g_bmpcache_count[id];
if (IS_SET(p_idx))
g_bmpcache[id][p_idx].next = n_idx;
else
g_bmpcache_lru[id] = n_idx;
if (IS_SET(n_idx))
g_bmpcache[id][n_idx].previous = p_idx;
else
g_bmpcache_mru[id] = p_idx;
}
else
{
p_idx = NOT_SET;
n_idx = g_bmpcache_lru[id];
}
if (IS_SET(n_idx)) {
/* remove */
--g_bmpcache_count[id];
if (IS_SET(p_idx))
g_bmpcache[id][p_idx].next = n_idx;
else
g_bmpcache_lru[id] = n_idx;
if (IS_SET(n_idx))
g_bmpcache[id][n_idx].previous = p_idx;
else
g_bmpcache_mru[id] = p_idx;
} else {
p_idx = NOT_SET;
n_idx = g_bmpcache_lru[id];
}
if (bump >= 0)
{
for (n = 0; n < bump && IS_SET(n_idx); n++)
{
p_idx = n_idx;
n_idx = g_bmpcache[id][p_idx].next;
}
}
else
{
p_idx = g_bmpcache_mru[id];
n_idx = NOT_SET;
}
if (bump >= 0) {
for (n = 0; n < bump && IS_SET(n_idx); n++) {
p_idx = n_idx;
n_idx = g_bmpcache[id][p_idx].next;
}
} else {
p_idx = g_bmpcache_mru[id];
n_idx = NOT_SET;
}
/* insert */
++g_bmpcache_count[id];
g_bmpcache[id][idx].previous = p_idx;
g_bmpcache[id][idx].next = n_idx;
/* insert */
++g_bmpcache_count[id];
g_bmpcache[id][idx].previous = p_idx;
g_bmpcache[id][idx].next = n_idx;
if (p_idx >= 0)
g_bmpcache[id][p_idx].next = idx;
else
g_bmpcache_lru[id] = idx;
if (p_idx >= 0)
g_bmpcache[id][p_idx].next = idx;
else
g_bmpcache_lru[id] = idx;
if (n_idx >= 0)
g_bmpcache[id][n_idx].previous = idx;
else
g_bmpcache_mru[id] = idx;
if (n_idx >= 0)
g_bmpcache[id][n_idx].previous = idx;
else
g_bmpcache_mru[id] = idx;
}
/* Evict the least-recently used bitmap from the cache */
void
cache_evict_bitmap(uint8 id)
{
uint16 idx;
int n_idx;
void cache_evict_bitmap(uint8_t id) {
uint16_t idx;
int n_idx;
if (!IS_PERSISTENT(id))
return;
if (!IS_PERSISTENT(id))
return;
idx = g_bmpcache_lru[id];
n_idx = g_bmpcache[id][idx].next;
idx = g_bmpcache_lru[id];
n_idx = g_bmpcache[id][idx].next;
logger(Core, Debug, "cache_evict_bitmap(), id=%d idx=%d n_idx=%d bmp=%p", id, idx, n_idx,
g_bmpcache[id][idx].bitmap);
logger(Core, Debug, "cache_evict_bitmap(), id=%d idx=%d n_idx=%d bmp=%p", id, idx, n_idx,
g_bmpcache[id][idx].bitmap);
ui_destroy_bitmap(g_bmpcache[id][idx].bitmap);
--g_bmpcache_count[id];
g_bmpcache[id][idx].bitmap = 0;
ui_destroy_bitmap(g_bmpcache[id][idx].bitmap);
--g_bmpcache_count[id];
g_bmpcache[id][idx].bitmap = 0;
g_bmpcache_lru[id] = n_idx;
g_bmpcache[id][n_idx].previous = NOT_SET;
g_bmpcache_lru[id] = n_idx;
g_bmpcache[id][n_idx].previous = NOT_SET;
pstcache_touch_bitmap(id, idx, 0);
pstcache_touch_bitmap(id, idx, 0);
}
/* Retrieve a bitmap from the cache */
RD_HBITMAP
cache_get_bitmap(uint8 id, uint16 idx)
{
if ((id < NUM_ELEMENTS(g_bmpcache)) && (idx < NUM_ELEMENTS(g_bmpcache[0])))
{
if (g_bmpcache[id][idx].bitmap || pstcache_load_bitmap(id, idx))
{
if (IS_PERSISTENT(id))
cache_bump_bitmap(id, idx, BUMP_COUNT);
RD_HBITMAP cache_get_bitmap(uint8_t id, uint16_t idx) {
if ((id < NUM_ELEMENTS(g_bmpcache)) && (idx < NUM_ELEMENTS(g_bmpcache[0]))) {
if (g_bmpcache[id][idx].bitmap || pstcache_load_bitmap(id, idx)) {
if (IS_PERSISTENT(id))
cache_bump_bitmap(id, idx, BUMP_COUNT);
return g_bmpcache[id][idx].bitmap;
}
}
else if ((id < NUM_ELEMENTS(g_volatile_bc)) && (idx == 0x7fff))
{
return g_volatile_bc[id];
}
return g_bmpcache[id][idx].bitmap;
}
} else if ((id < NUM_ELEMENTS(g_volatile_bc)) && (idx == 0x7fff)) {
return g_volatile_bc[id];
}
logger(Core, Debug, "cache_get_bitmap(), id=%d, idx=%d", id, idx);
logger(Core, Debug, "cache_get_bitmap(), id=%d, idx=%d", id, idx);
return NULL;
return NULL;
}
/* Store a bitmap in the cache */
void
cache_put_bitmap(uint8 id, uint16 idx, RD_HBITMAP bitmap)
{
RD_HBITMAP old;
void cache_put_bitmap(uint8_t id, uint16_t idx, RD_HBITMAP bitmap) {
RD_HBITMAP old;
if ((id < NUM_ELEMENTS(g_bmpcache)) && (idx < NUM_ELEMENTS(g_bmpcache[0])))
{
old = g_bmpcache[id][idx].bitmap;
if (old != NULL)
ui_destroy_bitmap(old);
g_bmpcache[id][idx].bitmap = bitmap;
if ((id < NUM_ELEMENTS(g_bmpcache)) && (idx < NUM_ELEMENTS(g_bmpcache[0]))) {
old = g_bmpcache[id][idx].bitmap;
if (old != NULL)
ui_destroy_bitmap(old);
g_bmpcache[id][idx].bitmap = bitmap;
if (IS_PERSISTENT(id))
{
if (old == NULL)
g_bmpcache[id][idx].previous = g_bmpcache[id][idx].next = NOT_SET;
if (IS_PERSISTENT(id)) {
if (old == NULL)
g_bmpcache[id][idx].previous = g_bmpcache[id][idx].next = NOT_SET;
cache_bump_bitmap(id, idx, TO_TOP);
if (g_bmpcache_count[id] > BMPCACHE2_C2_CELLS)
cache_evict_bitmap(id);
}
}
else if ((id < NUM_ELEMENTS(g_volatile_bc)) && (idx == 0x7fff))
{
old = g_volatile_bc[id];
if (old != NULL)
ui_destroy_bitmap(old);
g_volatile_bc[id] = bitmap;
}
else
{
logger(Core, Error, "cache_put_bitmap(), failed, id=%d, idx=%d\n", id, idx);
}
cache_bump_bitmap(id, idx, TO_TOP);
if (g_bmpcache_count[id] > BMPCACHE2_C2_CELLS)
cache_evict_bitmap(id);
}
} else if ((id < NUM_ELEMENTS(g_volatile_bc)) && (idx == 0x7fff)) {
old = g_volatile_bc[id];
if (old != NULL)
ui_destroy_bitmap(old);
g_volatile_bc[id] = bitmap;
} else {
logger(Core, Error, "cache_put_bitmap(), failed, id=%d, idx=%d\n", id, idx);
}
}
/* Updates the persistent bitmap cache MRU information on exit */
void
cache_save_state(void)
{
uint32 id = 0, t = 0;
int idx;
void cache_save_state(void) {
uint32_t id = 0, t = 0;
int idx;
for (id = 0; id < NUM_ELEMENTS(g_bmpcache); id++)
if (IS_PERSISTENT(id))
{
logger(Core, Debug,
"cache_save_state(), saving cache state for bitmap cache %d", id);
idx = g_bmpcache_lru[id];
while (idx >= 0)
{
pstcache_touch_bitmap(id, idx, ++t);
idx = g_bmpcache[id][idx].next;
}
logger(Core, Debug, "cache_save_state(), %d stamps written", t);
}
for (id = 0; id < NUM_ELEMENTS(g_bmpcache); id++)
if (IS_PERSISTENT(id)) {
logger(Core, Debug,
"cache_save_state(), saving cache state for bitmap cache %d", id);
idx = g_bmpcache_lru[id];
while (idx >= 0) {
pstcache_touch_bitmap(id, idx, ++t);
idx = g_bmpcache[id][idx].next;
}
logger(Core, Debug, "cache_save_state(), %d stamps written", t);
}
}
/* FONT CACHE */
static FONTGLYPH g_fontcache[12][256];
/* Retrieve a glyph from the font cache */
FONTGLYPH *
cache_get_font(uint8 font, uint16 character)
{
FONTGLYPH *glyph;
FONTGLYPH *cache_get_font(uint8_t font, uint16_t character) {
if ((font < NUM_ELEMENTS(g_fontcache)) && (character < NUM_ELEMENTS(g_fontcache[0]))) {
FONTGLYPH *glyph = &g_fontcache[font][character];
if (glyph->pixmap != NULL)
return glyph;
}
if ((font < NUM_ELEMENTS(g_fontcache)) && (character < NUM_ELEMENTS(g_fontcache[0])))
{
glyph = &g_fontcache[font][character];
if (glyph->pixmap != NULL)
return glyph;
}
logger(Core, Debug, "cache_get_font(), font=%d, char=%d", font, character);
return NULL;
logger(Core, Debug, "cache_get_font(), font=%d, char=%d", font, character);
return NULL;
}
/* Store a glyph in the font cache */
void
cache_put_font(uint8 font, uint16 character, uint16 offset,
uint16 baseline, uint16 width, uint16 height, RD_HGLYPH pixmap)
{
FONTGLYPH *glyph;
void cache_put_font(uint8_t font, uint16_t character, uint16_t offset,
uint16_t baseline, uint16_t width, uint16_t height, RD_HGLYPH pixmap) {
if ((font < NUM_ELEMENTS(g_fontcache)) && (character < NUM_ELEMENTS(g_fontcache[0]))) {
FONTGLYPH *glyph = &g_fontcache[font][character];
if (glyph->pixmap != NULL)
ui_destroy_glyph(glyph->pixmap);
if ((font < NUM_ELEMENTS(g_fontcache)) && (character < NUM_ELEMENTS(g_fontcache[0])))
{
glyph = &g_fontcache[font][character];
if (glyph->pixmap != NULL)
ui_destroy_glyph(glyph->pixmap);
glyph->offset = offset;
glyph->baseline = baseline;
glyph->width = width;
glyph->height = height;
glyph->pixmap = pixmap;
}
else
{
logger(Core, Error, "cache_put_font(), failed, font=%d, char=%d", font, character);
}
glyph->offset = offset;
glyph->baseline = baseline;
glyph->width = width;
glyph->height = height;
glyph->pixmap = pixmap;
} else {
logger(Core, Error, "cache_put_font(), failed, font=%d, char=%d", font, character);
}
}
/* TEXT CACHE */
static DATABLOB g_textcache[256];
/* Retrieve a text item from the cache */
DATABLOB *
cache_get_text(uint8 cache_id)
{
DATABLOB *text;
text = &g_textcache[cache_id];
return text;
DATABLOB *cache_get_text(uint8_t cache_id) {
return &g_textcache[cache_id];
}
/* Store a text item in the cache */
void
cache_put_text(uint8 cache_id, void *data, int length)
{
DATABLOB *text;
text = &g_textcache[cache_id];
if (text->data != NULL)
xfree(text->data);
text->data = xmalloc(length);
text->size = length;
memcpy(text->data, data, length);
void cache_put_text(uint8_t cache_id, void *data, int length) {
if (cache_id < NUM_ELEMENTS(g_textcache)) {
DATABLOB *text = &g_textcache[cache_id];
if (text->data != NULL)
xfree(text->data);
text->data = xmalloc(length);
text->size = length;
memcpy(text->data, data, length);
} else {
logger(Core, Error, "cache_put_text(), failed, cache_id=%d", cache_id);
}
}
/* DESKTOP CACHE */
static uint8 g_deskcache[0x38400 * 4];
static uint8_t g_deskcache[0x38400 * 4];
/* Retrieve desktop data from the cache */
uint8 *
cache_get_desktop(uint32 offset, int cx, int cy, int bytes_per_pixel)
{
int length = cx * cy * bytes_per_pixel;
uint8_t *cache_get_desktop(uint32_t offset, int cx, int cy, int bytes_per_pixel) {
int length = cx * cy * bytes_per_pixel;
if (offset > sizeof(g_deskcache))
offset = 0;
if (offset > sizeof(g_deskcache))
offset = 0;
if ((offset + length) <= sizeof(g_deskcache))
{
return &g_deskcache[offset];
}
if ((offset + length) <= sizeof(g_deskcache)) {
return &g_deskcache[offset];
}
logger(Core, Debug, "cache_get_desktop(), offset=%d, length=%d", offset, length);
return NULL;
logger(Core, Debug, "cache_get_desktop(), offset=%d, length=%d", offset, length);
return NULL;
}
/* Store desktop data in the cache */
void
cache_put_desktop(uint32 offset, int cx, int cy, int scanline, int bytes_per_pixel, uint8 * data)
{
int length = cx * cy * bytes_per_pixel;
void cache_put_desktop(uint32_t offset, int cx, int cy, int scanline, int bytes_per_pixel, uint8_t *data) {
int length = cx * cy * bytes_per_pixel;
if (offset > sizeof(g_deskcache))
offset = 0;
if (offset > sizeof(g_deskcache))
offset = 0;
if ((offset + length) <= sizeof(g_deskcache))
{
cx *= bytes_per_pixel;
while (cy--)
{
memcpy(&g_deskcache[offset], data, cx);
data += scanline;
offset += cx;
}
}
else
{
logger(Core, Error, "cache_put_desktop(), offset=%d, length=%d", offset, length);
}
if ((offset + length) <= sizeof(g_deskcache)) {
cx *= bytes_per_pixel;
while (cy--) {
memcpy(&g_deskcache[offset], data, cx);
data += scanline;
offset += cx;
}
} else {
logger(Core, Error, "cache_put_desktop(), offset=%d, length=%d", offset, length);
}
}
/* CURSOR CACHE */
static RD_HCURSOR g_cursorcache[0x20];
/* Retrieve cursor from cache */
RD_HCURSOR
cache_get_cursor(uint16 cache_idx)
{
RD_HCURSOR cursor;
RD_HCURSOR cache_get_cursor(uint16_t cache_idx) {
if (cache_idx < NUM_ELEMENTS(g_cursorcache)) {
RD_HCURSOR cursor = g_cursorcache[cache_idx];
if (cursor != NULL)
return cursor;
}
if (cache_idx < NUM_ELEMENTS(g_cursorcache))
{
cursor = g_cursorcache[cache_idx];
if (cursor != NULL)
return cursor;
}
logger(Core, Debug, "cache_get_cursor(), idx=%d", cache_idx);
return NULL;
logger(Core, Debug, "cache_get_cursor(), idx=%d", cache_idx);
return NULL;
}
/* Store cursor in cache */
void
cache_put_cursor(uint16 cache_idx, RD_HCURSOR cursor)
{
RD_HCURSOR old;
void cache_put_cursor(uint16_t cache_idx, RD_HCURSOR cursor) {
if (cache_idx < NUM_ELEMENTS(g_cursorcache)) {
RD_HCURSOR old = g_cursorcache[cache_idx];
if (old != NULL)
ui_destroy_cursor(old);
if (cache_idx < NUM_ELEMENTS(g_cursorcache))
{
old = g_cursorcache[cache_idx];
if (old != NULL)
ui_destroy_cursor(old);
g_cursorcache[cache_idx] = cursor;
}
else
{
logger(Core, Error, "cache_put_cursor(), failed, idx=%d", cache_idx);
}
g_cursorcache[cache_idx] = cursor;
} else {
logger(Core, Error, "cache_put_cursor(), failed, idx=%d", cache_idx);
}
}
/* BRUSH CACHE */
@ -441,37 +361,26 @@ cache_put_cursor(uint16 cache_idx, RD_HCURSOR cursor)
static BRUSHDATA g_brushcache[2][64];
/* Retrieve brush from cache */
BRUSHDATA *
cache_get_brush_data(uint8 colour_code, uint8 idx)
{
colour_code = colour_code == 1 ? 0 : 1;
if (idx < NUM_ELEMENTS(g_brushcache[0]))
{
return &g_brushcache[colour_code][idx];
}
logger(Core, Debug, "cache_get_brush_data(), colour=%d, idx=%d", colour_code, idx);
return NULL;
BRUSHDATA *cache_get_brush_data(uint8_t colour_code, uint8_t idx) {
colour_code = colour_code == 1 ? 0 : 1;
if (idx < NUM_ELEMENTS(g_brushcache[0])) {
return &g_brushcache[colour_code][idx];
}
logger(Core, Debug, "cache_get_brush_data(), colour=%d, idx=%d", colour_code, idx);
return NULL;
}
/* Store brush in cache */
/* this function takes over the data pointer in struct, e.g. caller gives it up */
void
cache_put_brush_data(uint8 colour_code, uint8 idx, BRUSHDATA * brush_data)
{
BRUSHDATA *bd;
colour_code = colour_code == 1 ? 0 : 1;
if (idx < NUM_ELEMENTS(g_brushcache[0]))
{
bd = &g_brushcache[colour_code][idx];
if (bd->data != 0)
{
xfree(bd->data);
}
memcpy(bd, brush_data, sizeof(BRUSHDATA));
}
else
{
logger(Core, Error, "cache_put_brush_data(), colour=%d, idx=%d", colour_code, idx);
}
void cache_put_brush_data(uint8_t colour_code, uint8_t idx, BRUSHDATA *brush_data) {
colour_code = colour_code == 1 ? 0 : 1;
if (idx < NUM_ELEMENTS(g_brushcache[0])) {
BRUSHDATA *bd = &g_brushcache[colour_code][idx];
if (bd->data != 0) {
xfree(bd->data);
}
memcpy(bd, brush_data, sizeof(BRUSHDATA));
} else {
logger(Core, Error, "cache_put_brush_data(), colour=%d, idx=%d", colour_code, idx);
}
}

View File

@ -1,4 +1,4 @@
AC_INIT(rdesktop, 1.8.99)
AC_INIT(rdesktop, 1.9.0)
AC_CONFIG_SRCDIR([rdesktop.c])

View File

@ -1,3 +1,22 @@
rdesktop (1.9.0)
* Use GnuTLS and nettle instead of OpenSSL
* Improved certificate handling
* Add support for dynamic resize of sessions
* Add support for alpha cursors
* Add PulseAudio support
* Add Kerberos support on macOS
* Kerberos support no longer requires libgssglue
* Remove support for rdesktop's custom microphone extension
* Several fixes to improve compatibility with modern desktops
* macOS compatibility fixes
* Improved handling of redirections
* Many smart card bug fixes
* Many disk redirection bug fixes
* Improved logging
* Lots of other small bug fixes
-- Pierre Ossman <ossman@cendio.se> 2019-09-18
rdesktop (1.8.6)
* Fix protocol code handling new licenses

View File

@ -1,6 +1,6 @@
Summary: Remote Desktop Protocol client
Name: rdesktop
Version: 1.8.99
Version: 1.9.0
Release: 1
License: GPL; see COPYING
Group: Applications/Communications

17
ssl.c
View File

@ -90,9 +90,8 @@ rdssl_rsa_encrypt(uint8 * out, uint8 * in, int len, uint32 modulus_size, uint8 *
mpz_init(exp);
mpz_init(mod);
mpz_import(mod, modulus_size, 1, sizeof(modulus[0]), 0, 0, modulus);
// TODO: Need exponent size
mpz_import(exp, 3, 1, sizeof(exponent[0]), 0, 0, exponent);
mpz_import(mod, modulus_size, -1, sizeof(modulus[0]), 0, 0, modulus);
mpz_import(exp, SEC_EXPONENT_SIZE, -1, sizeof(exponent[0]), 0, 0, exponent);
mpz_import(x, len, -1, sizeof(in[0]), 0, 0, in);
@ -308,9 +307,15 @@ rdssl_rkey_get_exp_mod(RDSSL_RKEY * rkey, uint8 * exponent, uint32 max_exp_len,
{
size_t outlen;
// TODO: Check size before exporing
mpz_export(modulus, &outlen, 1, sizeof(uint8), 0, 0, rkey->n);
mpz_export(exponent, &outlen, 1, sizeof(uint8), 0, 0, rkey->e);
outlen = (mpz_sizeinbase(rkey->n, 2) + 7) / 8;
if (outlen > max_mod_len)
return 1;
outlen = (mpz_sizeinbase(rkey->e, 2) + 7) / 8;
if (outlen > max_exp_len)
return 1;
mpz_export(modulus, &outlen, -1, sizeof(uint8), 0, 0, rkey->n);
mpz_export(exponent, &outlen, -1, sizeof(uint8), 0, 0, rkey->e);
/*
* Note that gnutls_x509_crt_get_pk_rsa_raw() exports modulus with additional

5
tcp.c
View File

@ -55,7 +55,10 @@
#define INADDR_NONE ((unsigned long) -1)
#endif
#define GNUTLS_PRIORITY "NORMAL"
/* Windows' self signed certificates omit the required Digital
Signature key usage flag, and only %COMPAT makes GnuTLS ignore
that violation. */
#define GNUTLS_PRIORITY "NORMAL:%COMPAT"
#ifdef IPv6
static struct addrinfo *g_server_address = NULL;

View File

@ -1027,8 +1027,8 @@ utils_cert_handle_exception(gnutls_session_t session, unsigned int status,
cert_invalid_reasons, sizeof(cert_invalid_reasons));
snprintf(message, sizeof(message),
"ATTENTION! The server uses and invalid security certificate which can not be trusted for\n"
"the following identified reasons(s);\n\n"
"ATTENTION! The server uses an invalid security certificate which can not be trusted for\n"
"the following identified reason(s);\n\n"
"%s"
"\n"
REVIEW_CERT_TEXT