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

190
asn.c
View File

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

65
asn.h
View File

@ -16,8 +16,8 @@
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef _RDASN_H #ifndef RDASN_H
#define _RDASN_H #define RDASN_H
#include <gnutls/gnutls.h> #include <gnutls/gnutls.h>
#include <libtasn1.h> #include <libtasn1.h>
@ -32,14 +32,65 @@ extern "C" {
#define OID_SHA_WITH_RSA_SIGNATURE "1.3.14.3.2.15" #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_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 #ifdef __cplusplus
} }
#endif #endif
#endif /* _RDASN_H */ #endif /* RDASN_H */

775
bitmap.c
View File

@ -17,10 +17,6 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
/* three separate function for speed when decompressing the bitmaps
when modifying one function make the change in the others
jay.sorg@gmail.com */
/* indent is confused by this file */ /* indent is confused by this file */
/* *INDENT-OFF* */ /* *INDENT-OFF* */
@ -62,410 +58,20 @@
} \ } \
} }
/* 1 byte bitmap decompress */ #define OPCODE_FILL 0
#define OPCODE_MIX 1
#define OPCODE_FILL_OR_MIX 2
#define OPCODE_COLOUR 3
#define OPCODE_COPY 4
#define OPCODE_BICOLOUR 8
#define OPCODE_WHITE 0xd
#define OPCODE_BLACK 0xe
#define WHITE_PIXEL 0xff
#define BLACK_PIXEL 0
static RD_BOOL static RD_BOOL
bitmap_decompress1(uint8 * output, int width, int height, uint8 * input, int size) bitmap_decompress_n(uint8 *output, int width, int height, uint8 *input, int size, int bytes_per_pixel)
{
uint8 *end = input + size;
uint8 *prevline = NULL, *line = NULL;
int opcode, count, offset, isfillormix, x = width;
int lastopcode = -1, insertmix = False, bicolour = False;
uint8 code;
uint8 colour1 = 0, colour2 = 0;
uint8 mixmask, mask = 0;
uint8 mix = 0xff;
int fom_mask = 0;
while (input < end)
{
fom_mask = 0;
code = CVAL(input);
opcode = code >> 4;
/* Handle different opcode forms */
switch (opcode)
{
case 0xc:
case 0xd:
case 0xe:
opcode -= 6;
count = code & 0xf;
offset = 16;
break;
case 0xf:
opcode = code & 0xf;
if (opcode < 9)
{
count = CVAL(input);
count |= CVAL(input) << 8;
}
else
{
count = (opcode < 0xb) ? 8 : 1;
}
offset = 0;
break;
default:
opcode >>= 1;
count = code & 0x1f;
offset = 32;
break;
}
/* Handle strange cases for counts */
if (offset != 0)
{
isfillormix = ((opcode == 2) || (opcode == 7));
if (count == 0)
{
if (isfillormix)
count = CVAL(input) + 1;
else
count = CVAL(input) + offset;
}
else if (isfillormix)
{
count <<= 3;
}
}
/* Read preliminary data */
switch (opcode)
{
case 0: /* Fill */
if ((lastopcode == opcode) && !((x == width) && (prevline == NULL)))
insertmix = True;
break;
case 8: /* Bicolour */
colour1 = CVAL(input);
colour2 = CVAL(input);
break;
case 3: /* Colour */
colour2 = CVAL(input);
break;
case 6: /* SetMix/Mix */
case 7: /* SetMix/FillOrMix */
mix = CVAL(input);
opcode -= 5;
break;
case 9: /* FillOrMix_1 */
mask = 0x03;
opcode = 0x02;
fom_mask = 3;
break;
case 0x0a: /* FillOrMix_2 */
mask = 0x05;
opcode = 0x02;
fom_mask = 5;
break;
}
lastopcode = opcode;
mixmask = 0;
/* Output body */
while (count > 0)
{
if (x >= width)
{
if (height <= 0)
return False;
x = 0;
height--;
prevline = line;
line = output + height * width;
}
switch (opcode)
{
case 0: /* Fill */
if (insertmix)
{
if (prevline == NULL)
line[x] = mix;
else
line[x] = prevline[x] ^ mix;
insertmix = False;
count--;
x++;
}
if (prevline == NULL)
{
REPEAT(line[x] = 0)
}
else
{
REPEAT(line[x] = prevline[x])
}
break;
case 1: /* Mix */
if (prevline == NULL)
{
REPEAT(line[x] = mix)
}
else
{
REPEAT(line[x] = prevline[x] ^ mix)
}
break;
case 2: /* Fill or Mix */
if (prevline == NULL)
{
REPEAT
(
MASK_UPDATE();
if (mask & mixmask)
line[x] = mix;
else
line[x] = 0;
)
}
else
{
REPEAT
(
MASK_UPDATE();
if (mask & mixmask)
line[x] = prevline[x] ^ mix;
else
line[x] = prevline[x];
)
}
break;
case 3: /* Colour */
REPEAT(line[x] = colour2)
break;
case 4: /* Copy */
REPEAT(line[x] = CVAL(input))
break;
case 8: /* Bicolour */
REPEAT
(
if (bicolour)
{
line[x] = colour2;
bicolour = False;
}
else
{
line[x] = colour1;
bicolour = True; count++;
}
)
break;
case 0xd: /* White */
REPEAT(line[x] = 0xff)
break;
case 0xe: /* Black */
REPEAT(line[x] = 0)
break;
default:
logger(Core, Warning, "bitmap_decompress(), unhandled bitmap opcode 0x%x", opcode);
return False;
}
}
}
return True;
}
/* 2 byte bitmap decompress */
static RD_BOOL
bitmap_decompress2(uint8 * output, int width, int height, uint8 * input, int size)
{
uint8 *end = input + size;
uint16 *prevline = NULL, *line = NULL;
int opcode, count, offset, isfillormix, x = width;
int lastopcode = -1, insertmix = False, bicolour = False;
uint8 code;
uint16 colour1 = 0, colour2 = 0;
uint8 mixmask, mask = 0;
uint16 mix = 0xffff;
int fom_mask = 0;
while (input < end)
{
fom_mask = 0;
code = CVAL(input);
opcode = code >> 4;
/* Handle different opcode forms */
switch (opcode)
{
case 0xc:
case 0xd:
case 0xe:
opcode -= 6;
count = code & 0xf;
offset = 16;
break;
case 0xf:
opcode = code & 0xf;
if (opcode < 9)
{
count = CVAL(input);
count |= CVAL(input) << 8;
}
else
{
count = (opcode < 0xb) ? 8 : 1;
}
offset = 0;
break;
default:
opcode >>= 1;
count = code & 0x1f;
offset = 32;
break;
}
/* Handle strange cases for counts */
if (offset != 0)
{
isfillormix = ((opcode == 2) || (opcode == 7));
if (count == 0)
{
if (isfillormix)
count = CVAL(input) + 1;
else
count = CVAL(input) + offset;
}
else if (isfillormix)
{
count <<= 3;
}
}
/* Read preliminary data */
switch (opcode)
{
case 0: /* Fill */
if ((lastopcode == opcode) && !((x == width) && (prevline == NULL)))
insertmix = True;
break;
case 8: /* Bicolour */
CVAL2(input, colour1);
CVAL2(input, colour2);
break;
case 3: /* Colour */
CVAL2(input, colour2);
break;
case 6: /* SetMix/Mix */
case 7: /* SetMix/FillOrMix */
CVAL2(input, mix);
opcode -= 5;
break;
case 9: /* FillOrMix_1 */
mask = 0x03;
opcode = 0x02;
fom_mask = 3;
break;
case 0x0a: /* FillOrMix_2 */
mask = 0x05;
opcode = 0x02;
fom_mask = 5;
break;
}
lastopcode = opcode;
mixmask = 0;
/* Output body */
while (count > 0)
{
if (x >= width)
{
if (height <= 0)
return False;
x = 0;
height--;
prevline = line;
line = ((uint16 *) output) + height * width;
}
switch (opcode)
{
case 0: /* Fill */
if (insertmix)
{
if (prevline == NULL)
line[x] = mix;
else
line[x] = prevline[x] ^ mix;
insertmix = False;
count--;
x++;
}
if (prevline == NULL)
{
REPEAT(line[x] = 0)
}
else
{
REPEAT(line[x] = prevline[x])
}
break;
case 1: /* Mix */
if (prevline == NULL)
{
REPEAT(line[x] = mix)
}
else
{
REPEAT(line[x] = prevline[x] ^ mix)
}
break;
case 2: /* Fill or Mix */
if (prevline == NULL)
{
REPEAT
(
MASK_UPDATE();
if (mask & mixmask)
line[x] = mix;
else
line[x] = 0;
)
}
else
{
REPEAT
(
MASK_UPDATE();
if (mask & mixmask)
line[x] = prevline[x] ^ mix;
else
line[x] = prevline[x];
)
}
break;
case 3: /* Colour */
REPEAT(line[x] = colour2)
break;
case 4: /* Copy */
REPEAT(CVAL2(input, line[x]))
break;
case 8: /* Bicolour */
REPEAT
(
if (bicolour)
{
line[x] = colour2;
bicolour = False;
}
else
{
line[x] = colour1;
bicolour = True;
count++;
}
)
break;
case 0xd: /* White */
REPEAT(line[x] = 0xffff)
break;
case 0xe: /* Black */
REPEAT(line[x] = 0)
break;
default:
logger(Core, Warning, "bitmap_decompress2(), unhandled bitmap opcode 0x%x", opcode);
return False;
}
}
}
return True;
}
/* 3 byte bitmap decompress */
static RD_BOOL
bitmap_decompress3(uint8 * output, int width, int height, uint8 * input, int size)
{ {
uint8 *end = input + size; uint8 *end = input + size;
uint8 *prevline = NULL, *line = NULL; uint8 *prevline = NULL, *line = NULL;
@ -477,14 +83,12 @@ bitmap_decompress3(uint8 * output, int width, int height, uint8 * input, int siz
uint8 mix[3] = {0xff, 0xff, 0xff}; uint8 mix[3] = {0xff, 0xff, 0xff};
int fom_mask = 0; int fom_mask = 0;
while (input < end) while (input < end) {
{
fom_mask = 0; fom_mask = 0;
code = CVAL(input); code = CVAL(input);
opcode = code >> 4; opcode = code >> 4;
/* Handle different opcode forms */ /* Handle different opcode forms */
switch (opcode) switch (opcode) {
{
case 0xc: case 0xc:
case 0xd: case 0xd:
case 0xe: case 0xe:
@ -494,15 +98,11 @@ bitmap_decompress3(uint8 * output, int width, int height, uint8 * input, int siz
break; break;
case 0xf: case 0xf:
opcode = code & 0xf; opcode = code & 0xf;
if (opcode < 9) if (opcode < 9) {
{
count = CVAL(input); count = CVAL(input);
count |= CVAL(input) << 8; count |= CVAL(input) << 8;
} } else {
else count = (opcode < 0xb) ? 8 : 1;
{
count = (opcode <
0xb) ? 8 : 1;
} }
offset = 0; offset = 0;
break; break;
@ -513,239 +113,187 @@ bitmap_decompress3(uint8 * output, int width, int height, uint8 * input, int siz
break; break;
} }
/* Handle strange cases for counts */ /* Handle strange cases for counts */
if (offset != 0) if (offset != 0) {
{ isfillormix = ((opcode == OPCODE_FILL_OR_MIX) || (opcode == 7));
isfillormix = ((opcode == 2) || (opcode == 7)); if (count == 0) {
if (count == 0) if (isfillormix) {
{
if (isfillormix)
count = CVAL(input) + 1; count = CVAL(input) + 1;
else } else {
count = CVAL(input) + offset; count = CVAL(input) + offset;
} }
else if (isfillormix) } else if (isfillormix) {
{
count <<= 3; count <<= 3;
} }
} }
/* Read preliminary data */ /* Read preliminary data */
switch (opcode) switch (opcode) {
{ case OPCODE_FILL:
case 0: /* Fill */ if ((lastopcode == opcode) && !((x == width) && (prevline == NULL))) {
if ((lastopcode == opcode) && !((x == width) && (prevline == NULL)))
insertmix = True; insertmix = True;
}
break; break;
case 8: /* Bicolour */ case OPCODE_BICOLOUR:
colour1[0] = CVAL(input); for (int i = 0; i < bytes_per_pixel; i++) {
colour1[1] = CVAL(input); colour1[i] = CVAL(input);
colour1[2] = CVAL(input); colour2[i] = CVAL(input);
colour2[0] = CVAL(input); }
colour2[1] = CVAL(input);
colour2[2] = CVAL(input);
break; break;
case 3: /* Colour */ case OPCODE_COLOUR:
colour2[0] = CVAL(input); for (int i = 0; i < bytes_per_pixel; i++) {
colour2[1] = CVAL(input); colour2[i] = CVAL(input);
colour2[2] = CVAL(input); }
break; break;
case 6: /* SetMix/Mix */ case 6: /* SetMix/Mix */
case 7: /* SetMix/FillOrMix */ case 7: /* SetMix/FillOrMix */
mix[0] = CVAL(input); for (int i = 0; i < bytes_per_pixel; i++) {
mix[1] = CVAL(input); mix[i] = CVAL(input);
mix[2] = CVAL(input); }
opcode -= 5; opcode -= 5;
break; break;
case 9: /* FillOrMix_1 */ case 9: /* FillOrMix_1 */
mask = 0x03; mask = 0x03;
opcode = 0x02; opcode = OPCODE_FILL_OR_MIX;
fom_mask = 3; fom_mask = 3;
break; break;
case 0x0a: /* FillOrMix_2 */ case 0x0a: /* FillOrMix_2 */
mask = 0x05; mask = 0x05;
opcode = 0x02; opcode = OPCODE_FILL_OR_MIX;
fom_mask = 5; fom_mask = 5;
break; break;
} }
lastopcode = opcode; lastopcode = opcode;
mixmask = 0; mixmask = 0;
/* Output body */ /* Output body */
while (count > 0) while (count > 0) {
{ if (x >= width) {
if (x >= width) if (height <= 0) {
{
if (height <= 0)
return False; return False;
}
x = 0; x = 0;
height--; height--;
prevline = line; prevline = line;
line = output + height * (width * 3); line = output + height * (width * bytes_per_pixel);
} }
switch (opcode) switch (opcode) {
{ case OPCODE_FILL:
case 0: /* Fill */ if (insertmix) {
if (insertmix) if (prevline == NULL) {
{ for (int i = 0; i < bytes_per_pixel; i++) {
if (prevline == NULL) line[x * bytes_per_pixel + i] = mix[i];
{ }
line[x * 3] = mix[0]; } else {
line[x * 3 + 1] = mix[1]; for (int i = 0; i < bytes_per_pixel; i++) {
line[x * 3 + 2] = mix[2]; line[x * bytes_per_pixel + i] = prevline[x * bytes_per_pixel + i] ^ mix[i];
} }
else
{
line[x * 3] =
prevline[x * 3] ^ mix[0];
line[x * 3 + 1] =
prevline[x * 3 + 1] ^ mix[1];
line[x * 3 + 2] =
prevline[x * 3 + 2] ^ mix[2];
} }
insertmix = False; insertmix = False;
count--; count--;
x++; x++;
} }
if (prevline == NULL) if (prevline == NULL) {
{ REPEAT(
REPEAT for (int i = 0; i < bytes_per_pixel; i++) {
( line[x * bytes_per_pixel + i] = 0;
line[x * 3] = 0; }
line[x * 3 + 1] = 0; )
line[x * 3 + 2] = 0; } else {
) REPEAT(
for (int i = 0; i < bytes_per_pixel; i++) {
line[x * bytes_per_pixel + i] = prevline[x * bytes_per_pixel + i];
} }
else
{
REPEAT
(
line[x * 3] = prevline[x * 3];
line[x * 3 + 1] = prevline[x * 3 + 1];
line[x * 3 + 2] = prevline[x * 3 + 2];
) )
} }
break; break;
case 1: /* Mix */ case OPCODE_MIX:
if (prevline == NULL) if (prevline == NULL) {
{ REPEAT(
REPEAT for (int i = 0; i < bytes_per_pixel; i++) {
( line[x * bytes_per_pixel + i] = mix[i];
line[x * 3] = mix[0]; }
line[x * 3 + 1] = mix[1]; )
line[x * 3 + 2] = mix[2]; } else {
) REPEAT(
for (int i = 0; i < bytes_per_pixel; i++) {
line[x * bytes_per_pixel + i] = prevline[x * bytes_per_pixel + i] ^ mix[i];
} }
else
{
REPEAT
(
line[x * 3] =
prevline[x * 3] ^ mix[0];
line[x * 3 + 1] =
prevline[x * 3 + 1] ^ mix[1];
line[x * 3 + 2] =
prevline[x * 3 + 2] ^ mix[2];
) )
} }
break; break;
case 2: /* Fill or Mix */ case OPCODE_FILL_OR_MIX:
if (prevline == NULL) if (prevline == NULL) {
{ REPEAT(
REPEAT
(
MASK_UPDATE(); MASK_UPDATE();
if (mask & mixmask) if (mask & mixmask) {
{ for (int i = 0; i < bytes_per_pixel; i++) {
line[x * 3] = mix[0]; line[x * bytes_per_pixel + i] = mix[i];
line[x * 3 + 1] = mix[1]; }
line[x * 3 + 2] = mix[2]; } else {
for (int i = 0; i < bytes_per_pixel; i++) {
line[x * bytes_per_pixel + i] = 0;
} }
else
{
line[x * 3] = 0;
line[x * 3 + 1] = 0;
line[x * 3 + 2] = 0;
} }
) )
} } else {
else REPEAT(
{
REPEAT
(
MASK_UPDATE(); MASK_UPDATE();
if (mask & mixmask) if (mask & mixmask) {
{ for (int i = 0; i < bytes_per_pixel; i++) {
line[x * 3] = line[x * bytes_per_pixel + i] = prevline[x * bytes_per_pixel + i] ^ mix[i];
prevline[x * 3] ^ mix [0]; }
line[x * 3 + 1] = } else {
prevline[x * 3 + 1] ^ mix [1]; for (int i = 0; i < bytes_per_pixel; i++) {
line[x * 3 + 2] = line[x * bytes_per_pixel + i] = prevline[x * bytes_per_pixel + i];
prevline[x * 3 + 2] ^ mix [2];
} }
else
{
line[x * 3] =
prevline[x * 3];
line[x * 3 + 1] =
prevline[x * 3 + 1];
line[x * 3 + 2] =
prevline[x * 3 + 2];
} }
) )
} }
break; break;
case 3: /* Colour */ case OPCODE_COLOUR:
REPEAT REPEAT(
( for (int i = 0; i < bytes_per_pixel; i++) {
line[x * 3] = colour2 [0]; line[x * bytes_per_pixel + i] = colour2[i];
line[x * 3 + 1] = colour2 [1]; }
line[x * 3 + 2] = colour2 [2];
) )
break; break;
case 4: /* Copy */ case OPCODE_COPY:
REPEAT REPEAT(
( for (int i = 0; i < bytes_per_pixel; i++) {
line[x * 3] = CVAL(input); line[x * bytes_per_pixel + i] = CVAL(input);
line[x * 3 + 1] = CVAL(input); }
line[x * 3 + 2] = CVAL(input);
) )
break; break;
case 8: /* Bicolour */ case OPCODE_BICOLOUR:
REPEAT REPEAT(
( if (bicolour) {
if (bicolour) for (int i = 0; i < bytes_per_pixel; i++) {
{ line[x * bytes_per_pixel + i] = colour2[i];
line[x * 3] = colour2[0]; }
line[x * 3 + 1] = colour2[1];
line[x * 3 + 2] = colour2[2];
bicolour = False; bicolour = False;
} else {
for (int i = 0; i < bytes_per_pixel; i++) {
line[x * bytes_per_pixel + i] = colour1[i];
} }
else
{
line[x * 3] = colour1[0];
line[x * 3 + 1] = colour1[1];
line[x * 3 + 2] = colour1[2];
bicolour = True; bicolour = True;
count++; count++;
} }
) )
break; break;
case 0xd: /* White */ case OPCODE_WHITE:
REPEAT REPEAT(
( for (int i = 0; i < bytes_per_pixel; i++) {
line[x * 3] = 0xff; line[x * bytes_per_pixel + i] = WHITE_PIXEL;
line[x * 3 + 1] = 0xff; }
line[x * 3 + 2] = 0xff;
) )
break; break;
case 0xe: /* Black */ case OPCODE_BLACK:
REPEAT REPEAT(
( for (int i = 0; i < bytes_per_pixel; i++) {
line[x * 3] = 0; line[x * bytes_per_pixel + i] = BLACK_PIXEL;
line[x * 3 + 1] = 0; }
line[x * 3 + 2] = 0;
) )
break; break;
default: default:
logger(Core, Warning, "bitmap_decompress3(), unhandled bitmap opcode 0x%x", opcode); logger(Core, Warning, "bitmap_decompress_n(), unhandled bitmap opcode 0x%x", opcode);
return False; return False;
} }
} }
@ -755,7 +303,7 @@ bitmap_decompress3(uint8 * output, int width, int height, uint8 * input, int siz
/* decompress a colour plane */ /* decompress a colour plane */
static int static int
process_plane(uint8 * in, int width, int height, uint8 * out, int size) process_plane(uint8 *in, int width, int height, uint8 *out, int size)
{ {
UNUSED(size); UNUSED(size);
int indexw; int indexw;
@ -766,75 +314,61 @@ process_plane(uint8 * in, int width, int height, uint8 * out, int size)
int color; int color;
int x; int x;
int revcode; int revcode;
uint8 * last_line; uint8 *last_line;
uint8 * this_line; uint8 *this_line;
uint8 * org_in; uint8 *org_in;
uint8 * org_out; uint8 *org_out;
org_in = in; org_in = in;
org_out = out; org_out = out;
last_line = 0; last_line = 0;
indexh = 0; indexh = 0;
while (indexh < height) while (indexh < height) {
{
out = (org_out + width * height * 4) - ((indexh + 1) * width * 4); out = (org_out + width * height * 4) - ((indexh + 1) * width * 4);
color = 0; color = 0;
this_line = out; this_line = out;
indexw = 0; indexw = 0;
if (last_line == 0) if (last_line == 0) {
{ while (indexw < width) {
while (indexw < width)
{
code = CVAL(in); code = CVAL(in);
replen = code & 0xf; replen = code & 0xf;
collen = (code >> 4) & 0xf; collen = (code >> 4) & 0xf;
revcode = (replen << 4) | collen; revcode = (replen << 4) | collen;
if ((revcode <= 47) && (revcode >= 16)) if ((revcode <= 47) && (revcode >= 16)) {
{
replen = revcode; replen = revcode;
collen = 0; collen = 0;
} }
while (indexw < width && collen > 0) while (indexw < width && collen > 0) {
{
color = CVAL(in); color = CVAL(in);
*out = color; *out = color;
out += 4; out += 4;
indexw++; indexw++;
collen--; collen--;
} }
while (indexw < width && replen > 0) while (indexw < width && replen > 0) {
{
*out = color; *out = color;
out += 4; out += 4;
indexw++; indexw++;
replen--; replen--;
} }
} }
} } else {
else while (indexw < width) {
{
while (indexw < width)
{
code = CVAL(in); code = CVAL(in);
replen = code & 0xf; replen = code & 0xf;
collen = (code >> 4) & 0xf; collen = (code >> 4) & 0xf;
revcode = (replen << 4) | collen; revcode = (replen << 4) | collen;
if ((revcode <= 47) && (revcode >= 16)) if ((revcode <= 47) && (revcode >= 16)) {
{
replen = revcode; replen = revcode;
collen = 0; collen = 0;
} }
while (indexw < width && collen > 0) while (indexw < width && collen > 0) {
{
x = CVAL(in); x = CVAL(in);
if (x & 1) if (x & 1) {
{
x = x >> 1; x = x >> 1;
x = x + 1; x = x + 1;
color = -x; color = -x;
} } else {
else
{
x = x >> 1; x = x >> 1;
color = x; color = x;
} }
@ -844,8 +378,7 @@ process_plane(uint8 * in, int width, int height, uint8 * out, int size)
indexw++; indexw++;
collen--; collen--;
} }
while (indexw < width && replen > 0) while (indexw < width && replen > 0) {
{
x = last_line[indexw * 4] + color; x = last_line[indexw * 4] + color;
*out = x; *out = x;
out += 4; out += 4;
@ -857,20 +390,19 @@ process_plane(uint8 * in, int width, int height, uint8 * out, int size)
indexh++; indexh++;
last_line = this_line; last_line = this_line;
} }
return (int) (in - org_in); return (int)(in - org_in);
} }
/* 4 byte bitmap decompress */ /* 4 byte bitmap decompress */
static RD_BOOL static RD_BOOL
bitmap_decompress4(uint8 * output, int width, int height, uint8 * input, int size) bitmap_decompress4(uint8 *output, int width, int height, uint8 *input, int size)
{ {
int code; int code;
int bytes_pro; int bytes_pro;
int total_pro; int total_pro;
code = CVAL(input); code = CVAL(input);
if (code != 0x10) if (code != 0x10) {
{
return False; return False;
} }
total_pro = 1; total_pro = 1;
@ -890,20 +422,15 @@ bitmap_decompress4(uint8 * output, int width, int height, uint8 * input, int siz
/* main decompress function */ /* main decompress function */
RD_BOOL RD_BOOL
bitmap_decompress(uint8 * output, int width, int height, uint8 * input, int size, int Bpp) bitmap_decompress(uint8 *output, int width, int height, uint8 *input, int size, int Bpp)
{ {
RD_BOOL rv = False; RD_BOOL rv = False;
switch (Bpp) switch (Bpp) {
{
case 1: case 1:
rv = bitmap_decompress1(output, width, height, input, size);
break;
case 2: case 2:
rv = bitmap_decompress2(output, width, height, input, size);
break;
case 3: case 3:
rv = bitmap_decompress3(output, width, height, input, size); rv = bitmap_decompress_n(output, width, height, input, size, Bpp);
break; break;
case 4: case 4:
rv = bitmap_decompress4(output, width, height, input, size); rv = bitmap_decompress4(output, width, height, input, size);

235
cache.c
View File

@ -20,6 +20,9 @@
*/ */
#include "rdesktop.h" #include "rdesktop.h"
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
/* BITMAP CACHE */ /* BITMAP CACHE */
extern int g_pstcache_fd[]; extern int g_pstcache_fd[];
@ -30,22 +33,15 @@ extern int g_pstcache_fd[];
#define NOT_SET -1 #define NOT_SET -1
#define IS_SET(idx) (idx >= 0) #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 #define BUMP_COUNT 40
struct bmpcache_entry typedef struct bmpcache_entry {
{
RD_HBITMAP bitmap; RD_HBITMAP bitmap;
sint16 previous; int16_t previous;
sint16 next; 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 RD_HBITMAP g_volatile_bc[3];
static int g_bmpcache_lru[3] = { NOT_SET, NOT_SET, NOT_SET }; static int g_bmpcache_lru[3] = { NOT_SET, NOT_SET, NOT_SET };
@ -54,16 +50,13 @@ static int g_bmpcache_mru[3] = { NOT_SET, NOT_SET, NOT_SET };
static int g_bmpcache_count[3]; static int g_bmpcache_count[3];
/* Setup the bitmap cache lru/mru linked list */ /* Setup the bitmap cache lru/mru linked list */
void void cache_rebuild_bmpcache_linked_list(uint8_t id, int16_t *idx, int count) {
cache_rebuild_bmpcache_linked_list(uint8 id, sint16 * idx, int count)
{
int n = count, c = 0; int n = count, c = 0;
sint16 n_idx; int16_t n_idx;
/* find top, skip evicted bitmaps */ /* find top, skip evicted bitmaps */
while (--n >= 0 && g_bmpcache[id][idx[n]].bitmap == NULL); while (--n >= 0 && g_bmpcache[id][idx[n]].bitmap == NULL);
if (n < 0) if (n < 0) {
{
g_bmpcache_mru[id] = g_bmpcache_lru[id] = NOT_SET; g_bmpcache_mru[id] = g_bmpcache_lru[id] = NOT_SET;
return; return;
} }
@ -74,8 +67,7 @@ cache_rebuild_bmpcache_linked_list(uint8 id, sint16 * idx, int count)
c++; c++;
/* link list */ /* link list */
while (n >= 0) while (n >= 0) {
{
/* skip evicted bitmaps */ /* skip evicted bitmaps */
while (--n >= 0 && g_bmpcache[id][idx[n]].bitmap == NULL); while (--n >= 0 && g_bmpcache[id][idx[n]].bitmap == NULL);
@ -91,19 +83,16 @@ cache_rebuild_bmpcache_linked_list(uint8 id, sint16 * idx, int count)
g_bmpcache[id][n_idx].previous = NOT_SET; g_bmpcache[id][n_idx].previous = NOT_SET;
g_bmpcache_lru[id] = n_idx; g_bmpcache_lru[id] = n_idx;
if (c != g_bmpcache_count[id]) if (c != g_bmpcache_count[id]) {
{
logger(Core, Error, logger(Core, Error,
"cache_rebuild_bmpcache_linked_list(), %d in bitmap cache linked list, %d in ui cache...", "cache_rebuild_bmpcache_linked_list(), %d in bitmap cache linked list, %d in ui cache...",
c, g_bmpcache_count[id]); c, g_bmpcache_count[id]);
exit(EX_SOFTWARE); exit(EXIT_FAILURE);
} }
} }
/* Move a bitmap to a new position in the linked list. */ /* Move a bitmap to a new position in the linked list. */
void void cache_bump_bitmap(uint8_t id, uint16_t idx, int bump) {
cache_bump_bitmap(uint8 id, uint16 idx, int bump)
{
int p_idx, n_idx, n; int p_idx, n_idx, n;
if (!IS_PERSISTENT(id)) if (!IS_PERSISTENT(id))
@ -117,8 +106,7 @@ cache_bump_bitmap(uint8 id, uint16 idx, int bump)
n_idx = g_bmpcache[id][idx].next; n_idx = g_bmpcache[id][idx].next;
p_idx = g_bmpcache[id][idx].previous; p_idx = g_bmpcache[id][idx].previous;
if (IS_SET(n_idx)) if (IS_SET(n_idx)) {
{
/* remove */ /* remove */
--g_bmpcache_count[id]; --g_bmpcache_count[id];
if (IS_SET(p_idx)) if (IS_SET(p_idx))
@ -129,23 +117,17 @@ cache_bump_bitmap(uint8 id, uint16 idx, int bump)
g_bmpcache[id][n_idx].previous = p_idx; g_bmpcache[id][n_idx].previous = p_idx;
else else
g_bmpcache_mru[id] = p_idx; g_bmpcache_mru[id] = p_idx;
} } else {
else
{
p_idx = NOT_SET; p_idx = NOT_SET;
n_idx = g_bmpcache_lru[id]; n_idx = g_bmpcache_lru[id];
} }
if (bump >= 0) if (bump >= 0) {
{ for (n = 0; n < bump && IS_SET(n_idx); n++) {
for (n = 0; n < bump && IS_SET(n_idx); n++)
{
p_idx = n_idx; p_idx = n_idx;
n_idx = g_bmpcache[id][p_idx].next; n_idx = g_bmpcache[id][p_idx].next;
} }
} } else {
else
{
p_idx = g_bmpcache_mru[id]; p_idx = g_bmpcache_mru[id];
n_idx = NOT_SET; n_idx = NOT_SET;
} }
@ -167,10 +149,8 @@ cache_bump_bitmap(uint8 id, uint16 idx, int bump)
} }
/* Evict the least-recently used bitmap from the cache */ /* Evict the least-recently used bitmap from the cache */
void void cache_evict_bitmap(uint8_t id) {
cache_evict_bitmap(uint8 id) uint16_t idx;
{
uint16 idx;
int n_idx; int n_idx;
if (!IS_PERSISTENT(id)) if (!IS_PERSISTENT(id))
@ -193,21 +173,15 @@ cache_evict_bitmap(uint8 id)
} }
/* Retrieve a bitmap from the cache */ /* Retrieve a bitmap from the cache */
RD_HBITMAP RD_HBITMAP cache_get_bitmap(uint8_t id, uint16_t idx) {
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 ((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)) if (IS_PERSISTENT(id))
cache_bump_bitmap(id, idx, BUMP_COUNT); cache_bump_bitmap(id, idx, BUMP_COUNT);
return g_bmpcache[id][idx].bitmap; return g_bmpcache[id][idx].bitmap;
} }
} } else if ((id < NUM_ELEMENTS(g_volatile_bc)) && (idx == 0x7fff)) {
else if ((id < NUM_ELEMENTS(g_volatile_bc)) && (idx == 0x7fff))
{
return g_volatile_bc[id]; return g_volatile_bc[id];
} }
@ -217,20 +191,16 @@ cache_get_bitmap(uint8 id, uint16 idx)
} }
/* Store a bitmap in the cache */ /* Store a bitmap in the cache */
void void cache_put_bitmap(uint8_t id, uint16_t idx, RD_HBITMAP bitmap) {
cache_put_bitmap(uint8 id, uint16 idx, RD_HBITMAP bitmap)
{
RD_HBITMAP old; RD_HBITMAP old;
if ((id < NUM_ELEMENTS(g_bmpcache)) && (idx < NUM_ELEMENTS(g_bmpcache[0]))) if ((id < NUM_ELEMENTS(g_bmpcache)) && (idx < NUM_ELEMENTS(g_bmpcache[0]))) {
{
old = g_bmpcache[id][idx].bitmap; old = g_bmpcache[id][idx].bitmap;
if (old != NULL) if (old != NULL)
ui_destroy_bitmap(old); ui_destroy_bitmap(old);
g_bmpcache[id][idx].bitmap = bitmap; g_bmpcache[id][idx].bitmap = bitmap;
if (IS_PERSISTENT(id)) if (IS_PERSISTENT(id)) {
{
if (old == NULL) if (old == NULL)
g_bmpcache[id][idx].previous = g_bmpcache[id][idx].next = NOT_SET; g_bmpcache[id][idx].previous = g_bmpcache[id][idx].next = NOT_SET;
@ -238,35 +208,27 @@ cache_put_bitmap(uint8 id, uint16 idx, RD_HBITMAP bitmap)
if (g_bmpcache_count[id] > BMPCACHE2_C2_CELLS) if (g_bmpcache_count[id] > BMPCACHE2_C2_CELLS)
cache_evict_bitmap(id); cache_evict_bitmap(id);
} }
} } else if ((id < NUM_ELEMENTS(g_volatile_bc)) && (idx == 0x7fff)) {
else if ((id < NUM_ELEMENTS(g_volatile_bc)) && (idx == 0x7fff))
{
old = g_volatile_bc[id]; old = g_volatile_bc[id];
if (old != NULL) if (old != NULL)
ui_destroy_bitmap(old); ui_destroy_bitmap(old);
g_volatile_bc[id] = bitmap; g_volatile_bc[id] = bitmap;
} } else {
else
{
logger(Core, Error, "cache_put_bitmap(), failed, id=%d, idx=%d\n", id, idx); logger(Core, Error, "cache_put_bitmap(), failed, id=%d, idx=%d\n", id, idx);
} }
} }
/* Updates the persistent bitmap cache MRU information on exit */ /* Updates the persistent bitmap cache MRU information on exit */
void void cache_save_state(void) {
cache_save_state(void) uint32_t id = 0, t = 0;
{
uint32 id = 0, t = 0;
int idx; int idx;
for (id = 0; id < NUM_ELEMENTS(g_bmpcache); id++) for (id = 0; id < NUM_ELEMENTS(g_bmpcache); id++)
if (IS_PERSISTENT(id)) if (IS_PERSISTENT(id)) {
{
logger(Core, Debug, logger(Core, Debug,
"cache_save_state(), saving cache state for bitmap cache %d", id); "cache_save_state(), saving cache state for bitmap cache %d", id);
idx = g_bmpcache_lru[id]; idx = g_bmpcache_lru[id];
while (idx >= 0) while (idx >= 0) {
{
pstcache_touch_bitmap(id, idx, ++t); pstcache_touch_bitmap(id, idx, ++t);
idx = g_bmpcache[id][idx].next; idx = g_bmpcache[id][idx].next;
} }
@ -274,19 +236,13 @@ cache_save_state(void)
} }
} }
/* FONT CACHE */ /* FONT CACHE */
static FONTGLYPH g_fontcache[12][256]; static FONTGLYPH g_fontcache[12][256];
/* Retrieve a glyph from the font cache */ /* Retrieve a glyph from the font cache */
FONTGLYPH * FONTGLYPH *cache_get_font(uint8_t font, uint16_t character) {
cache_get_font(uint8 font, uint16 character) if ((font < NUM_ELEMENTS(g_fontcache)) && (character < NUM_ELEMENTS(g_fontcache[0]))) {
{ FONTGLYPH *glyph = &g_fontcache[font][character];
FONTGLYPH *glyph;
if ((font < NUM_ELEMENTS(g_fontcache)) && (character < NUM_ELEMENTS(g_fontcache[0])))
{
glyph = &g_fontcache[font][character];
if (glyph->pixmap != NULL) if (glyph->pixmap != NULL)
return glyph; return glyph;
} }
@ -296,15 +252,10 @@ cache_get_font(uint8 font, uint16 character)
} }
/* Store a glyph in the font cache */ /* Store a glyph in the font cache */
void void cache_put_font(uint8_t font, uint16_t character, uint16_t offset,
cache_put_font(uint8 font, uint16 character, uint16 offset, uint16_t baseline, uint16_t width, uint16_t height, RD_HGLYPH pixmap) {
uint16 baseline, uint16 width, uint16 height, RD_HGLYPH pixmap) if ((font < NUM_ELEMENTS(g_fontcache)) && (character < NUM_ELEMENTS(g_fontcache[0]))) {
{ FONTGLYPH *glyph = &g_fontcache[font][character];
FONTGLYPH *glyph;
if ((font < NUM_ELEMENTS(g_fontcache)) && (character < NUM_ELEMENTS(g_fontcache[0])))
{
glyph = &g_fontcache[font][character];
if (glyph->pixmap != NULL) if (glyph->pixmap != NULL)
ui_destroy_glyph(glyph->pixmap); ui_destroy_glyph(glyph->pixmap);
@ -313,56 +264,44 @@ cache_put_font(uint8 font, uint16 character, uint16 offset,
glyph->width = width; glyph->width = width;
glyph->height = height; glyph->height = height;
glyph->pixmap = pixmap; glyph->pixmap = pixmap;
} } else {
else
{
logger(Core, Error, "cache_put_font(), failed, font=%d, char=%d", font, character); logger(Core, Error, "cache_put_font(), failed, font=%d, char=%d", font, character);
} }
} }
/* TEXT CACHE */ /* TEXT CACHE */
static DATABLOB g_textcache[256]; static DATABLOB g_textcache[256];
/* Retrieve a text item from the cache */ /* Retrieve a text item from the cache */
DATABLOB * DATABLOB *cache_get_text(uint8_t cache_id) {
cache_get_text(uint8 cache_id) return &g_textcache[cache_id];
{
DATABLOB *text;
text = &g_textcache[cache_id];
return text;
} }
/* Store a text item in the cache */ /* Store a text item in the cache */
void void cache_put_text(uint8_t cache_id, void *data, int length) {
cache_put_text(uint8 cache_id, void *data, int length) if (cache_id < NUM_ELEMENTS(g_textcache)) {
{ DATABLOB *text = &g_textcache[cache_id];
DATABLOB *text;
text = &g_textcache[cache_id];
if (text->data != NULL) if (text->data != NULL)
xfree(text->data); xfree(text->data);
text->data = xmalloc(length); text->data = xmalloc(length);
text->size = length; text->size = length;
memcpy(text->data, data, length); memcpy(text->data, data, length);
} else {
logger(Core, Error, "cache_put_text(), failed, cache_id=%d", cache_id);
}
} }
/* DESKTOP CACHE */ /* DESKTOP CACHE */
static uint8 g_deskcache[0x38400 * 4]; static uint8_t g_deskcache[0x38400 * 4];
/* Retrieve desktop data from the cache */ /* Retrieve desktop data from the cache */
uint8 * uint8_t *cache_get_desktop(uint32_t offset, int cx, int cy, int bytes_per_pixel) {
cache_get_desktop(uint32 offset, int cx, int cy, int bytes_per_pixel)
{
int length = cx * cy * bytes_per_pixel; int length = cx * cy * bytes_per_pixel;
if (offset > sizeof(g_deskcache)) if (offset > sizeof(g_deskcache))
offset = 0; offset = 0;
if ((offset + length) <= sizeof(g_deskcache)) if ((offset + length) <= sizeof(g_deskcache)) {
{
return &g_deskcache[offset]; return &g_deskcache[offset];
} }
@ -371,43 +310,31 @@ cache_get_desktop(uint32 offset, int cx, int cy, int bytes_per_pixel)
} }
/* Store desktop data in the cache */ /* Store desktop data in the cache */
void void cache_put_desktop(uint32_t offset, int cx, int cy, int scanline, int bytes_per_pixel, uint8_t *data) {
cache_put_desktop(uint32 offset, int cx, int cy, int scanline, int bytes_per_pixel, uint8 * data)
{
int length = cx * cy * bytes_per_pixel; int length = cx * cy * bytes_per_pixel;
if (offset > sizeof(g_deskcache)) if (offset > sizeof(g_deskcache))
offset = 0; offset = 0;
if ((offset + length) <= sizeof(g_deskcache)) if ((offset + length) <= sizeof(g_deskcache)) {
{
cx *= bytes_per_pixel; cx *= bytes_per_pixel;
while (cy--) while (cy--) {
{
memcpy(&g_deskcache[offset], data, cx); memcpy(&g_deskcache[offset], data, cx);
data += scanline; data += scanline;
offset += cx; offset += cx;
} }
} } else {
else
{
logger(Core, Error, "cache_put_desktop(), offset=%d, length=%d", offset, length); logger(Core, Error, "cache_put_desktop(), offset=%d, length=%d", offset, length);
} }
} }
/* CURSOR CACHE */ /* CURSOR CACHE */
static RD_HCURSOR g_cursorcache[0x20]; static RD_HCURSOR g_cursorcache[0x20];
/* Retrieve cursor from cache */ /* Retrieve cursor from cache */
RD_HCURSOR RD_HCURSOR cache_get_cursor(uint16_t cache_idx) {
cache_get_cursor(uint16 cache_idx) if (cache_idx < NUM_ELEMENTS(g_cursorcache)) {
{ RD_HCURSOR cursor = g_cursorcache[cache_idx];
RD_HCURSOR cursor;
if (cache_idx < NUM_ELEMENTS(g_cursorcache))
{
cursor = g_cursorcache[cache_idx];
if (cursor != NULL) if (cursor != NULL)
return cursor; return cursor;
} }
@ -417,21 +344,14 @@ cache_get_cursor(uint16 cache_idx)
} }
/* Store cursor in cache */ /* Store cursor in cache */
void void cache_put_cursor(uint16_t cache_idx, RD_HCURSOR cursor) {
cache_put_cursor(uint16 cache_idx, RD_HCURSOR cursor) if (cache_idx < NUM_ELEMENTS(g_cursorcache)) {
{ RD_HCURSOR old = g_cursorcache[cache_idx];
RD_HCURSOR old;
if (cache_idx < NUM_ELEMENTS(g_cursorcache))
{
old = g_cursorcache[cache_idx];
if (old != NULL) if (old != NULL)
ui_destroy_cursor(old); ui_destroy_cursor(old);
g_cursorcache[cache_idx] = cursor; g_cursorcache[cache_idx] = cursor;
} } else {
else
{
logger(Core, Error, "cache_put_cursor(), failed, idx=%d", cache_idx); logger(Core, Error, "cache_put_cursor(), failed, idx=%d", cache_idx);
} }
} }
@ -441,12 +361,9 @@ cache_put_cursor(uint16 cache_idx, RD_HCURSOR cursor)
static BRUSHDATA g_brushcache[2][64]; static BRUSHDATA g_brushcache[2][64];
/* Retrieve brush from cache */ /* Retrieve brush from cache */
BRUSHDATA * BRUSHDATA *cache_get_brush_data(uint8_t colour_code, uint8_t idx) {
cache_get_brush_data(uint8 colour_code, uint8 idx)
{
colour_code = colour_code == 1 ? 0 : 1; colour_code = colour_code == 1 ? 0 : 1;
if (idx < NUM_ELEMENTS(g_brushcache[0])) if (idx < NUM_ELEMENTS(g_brushcache[0])) {
{
return &g_brushcache[colour_code][idx]; return &g_brushcache[colour_code][idx];
} }
logger(Core, Debug, "cache_get_brush_data(), colour=%d, idx=%d", colour_code, idx); logger(Core, Debug, "cache_get_brush_data(), colour=%d, idx=%d", colour_code, idx);
@ -455,23 +372,15 @@ cache_get_brush_data(uint8 colour_code, uint8 idx)
/* Store brush in cache */ /* Store brush in cache */
/* this function takes over the data pointer in struct, e.g. caller gives it up */ /* this function takes over the data pointer in struct, e.g. caller gives it up */
void void cache_put_brush_data(uint8_t colour_code, uint8_t idx, BRUSHDATA *brush_data) {
cache_put_brush_data(uint8 colour_code, uint8 idx, BRUSHDATA * brush_data)
{
BRUSHDATA *bd;
colour_code = colour_code == 1 ? 0 : 1; colour_code = colour_code == 1 ? 0 : 1;
if (idx < NUM_ELEMENTS(g_brushcache[0])) if (idx < NUM_ELEMENTS(g_brushcache[0])) {
{ BRUSHDATA *bd = &g_brushcache[colour_code][idx];
bd = &g_brushcache[colour_code][idx]; if (bd->data != 0) {
if (bd->data != 0)
{
xfree(bd->data); xfree(bd->data);
} }
memcpy(bd, brush_data, sizeof(BRUSHDATA)); memcpy(bd, brush_data, sizeof(BRUSHDATA));
} } else {
else
{
logger(Core, Error, "cache_put_brush_data(), colour=%d, idx=%d", colour_code, idx); 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]) 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) rdesktop (1.8.6)
* Fix protocol code handling new licenses * Fix protocol code handling new licenses

View File

@ -1,6 +1,6 @@
Summary: Remote Desktop Protocol client Summary: Remote Desktop Protocol client
Name: rdesktop Name: rdesktop
Version: 1.8.99 Version: 1.9.0
Release: 1 Release: 1
License: GPL; see COPYING License: GPL; see COPYING
Group: Applications/Communications 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(exp);
mpz_init(mod); mpz_init(mod);
mpz_import(mod, modulus_size, 1, sizeof(modulus[0]), 0, 0, modulus); mpz_import(mod, modulus_size, -1, sizeof(modulus[0]), 0, 0, modulus);
// TODO: Need exponent size mpz_import(exp, SEC_EXPONENT_SIZE, -1, sizeof(exponent[0]), 0, 0, exponent);
mpz_import(exp, 3, 1, sizeof(exponent[0]), 0, 0, exponent);
mpz_import(x, len, -1, sizeof(in[0]), 0, 0, in); 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; size_t outlen;
// TODO: Check size before exporing outlen = (mpz_sizeinbase(rkey->n, 2) + 7) / 8;
mpz_export(modulus, &outlen, 1, sizeof(uint8), 0, 0, rkey->n); if (outlen > max_mod_len)
mpz_export(exponent, &outlen, 1, sizeof(uint8), 0, 0, rkey->e); 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 * 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) #define INADDR_NONE ((unsigned long) -1)
#endif #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 #ifdef IPv6
static struct addrinfo *g_server_address = NULL; 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)); cert_invalid_reasons, sizeof(cert_invalid_reasons));
snprintf(message, sizeof(message), snprintf(message, sizeof(message),
"ATTENTION! The server uses and invalid security certificate which can not be trusted for\n" "ATTENTION! The server uses an invalid security certificate which can not be trusted for\n"
"the following identified reasons(s);\n\n" "the following identified reason(s);\n\n"
"%s" "%s"
"\n" "\n"
REVIEW_CERT_TEXT REVIEW_CERT_TEXT