summaryrefslogtreecommitdiffstats
path: root/libvncclient
diff options
context:
space:
mode:
Diffstat (limited to 'libvncclient')
-rw-r--r--libvncclient/Makefile.am29
-rw-r--r--libvncclient/corre.c4
-rw-r--r--libvncclient/hextile.c8
-rw-r--r--libvncclient/listen.c2
-rw-r--r--libvncclient/rfbproto.c130
-rw-r--r--libvncclient/rre.c4
-rw-r--r--libvncclient/tight.c11
-rw-r--r--libvncclient/tls_gnutls.c104
-rw-r--r--libvncclient/tls_openssl.c249
-rw-r--r--libvncclient/ultra.c4
-rw-r--r--libvncclient/vncviewer.c124
-rw-r--r--libvncclient/zlib.c2
-rw-r--r--libvncclient/zrle.c4
13 files changed, 404 insertions, 271 deletions
diff --git a/libvncclient/Makefile.am b/libvncclient/Makefile.am
deleted file mode 100644
index bc2420b..0000000
--- a/libvncclient/Makefile.am
+++ /dev/null
@@ -1,29 +0,0 @@
-AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/common
-
-if HAVE_GNUTLS
-TLSSRCS = tls_gnutls.c
-TLSLIBS = @GNUTLS_LIBS@
-else
-if HAVE_LIBSSL
-TLSSRCS = tls_openssl.c
-TLSLIBS = @SSL_LIBS@ @CRYPT_LIBS@
-else
-TLSSRCS = tls_none.c
-endif
-endif
-
-
-libvncclient_la_SOURCES=cursor.c listen.c rfbproto.c sockets.c vncviewer.c ../common/minilzo.c $(TLSSRCS)
-libvncclient_la_LIBADD=$(TLSLIBS)
-
-noinst_HEADERS=../common/lzodefs.h ../common/lzoconf.h ../common/minilzo.h tls.h
-
-rfbproto.o: rfbproto.c corre.c hextile.c rre.c tight.c zlib.c zrle.c ultra.c
-
-EXTRA_DIST=corre.c hextile.c rre.c tight.c zlib.c zrle.c ultra.c tls_gnutls.c tls_openssl.c tls_none.c
-
-$(libvncclient_la_OBJECTS): ../rfb/rfbclient.h
-
-lib_LTLIBRARIES=libvncclient.la
-libvncclient_la_LDFLAGS = -version-info 1:0:0
-
diff --git a/libvncclient/corre.c b/libvncclient/corre.c
index baf91cc..66e3b08 100644
--- a/libvncclient/corre.c
+++ b/libvncclient/corre.c
@@ -46,7 +46,7 @@ HandleCoRREBPP (rfbClient* client, int rx, int ry, int rw, int rh)
if (!ReadFromRFBServer(client, (char *)&pix, sizeof(pix)))
return FALSE;
- FillRectangle(client, rx, ry, rw, rh, pix);
+ client->GotFillRect(client, rx, ry, rw, rh, pix);
if (!ReadFromRFBServer(client, client->buffer, hdr.nSubrects * (4 + (BPP / 8))))
return FALSE;
@@ -61,7 +61,7 @@ HandleCoRREBPP (rfbClient* client, int rx, int ry, int rw, int rh)
w = *ptr++;
h = *ptr++;
- FillRectangle(client, rx+x, ry+y, w, h, pix);
+ client->GotFillRect(client, rx+x, ry+y, w, h, pix);
}
return TRUE;
diff --git a/libvncclient/hextile.c b/libvncclient/hextile.c
index 8698445..05a7cf5 100644
--- a/libvncclient/hextile.c
+++ b/libvncclient/hextile.c
@@ -55,7 +55,7 @@ HandleHextileBPP (rfbClient* client, int rx, int ry, int rw, int rh)
if (!ReadFromRFBServer(client, client->buffer, w * h * (BPP / 8)))
return FALSE;
- CopyRectangle(client, (uint8_t *)client->buffer, x, y, w, h);
+ client->GotBitmap(client, (uint8_t *)client->buffer, x, y, w, h);
continue;
}
@@ -64,7 +64,7 @@ HandleHextileBPP (rfbClient* client, int rx, int ry, int rw, int rh)
if (!ReadFromRFBServer(client, (char *)&bg, sizeof(bg)))
return FALSE;
- FillRectangle(client, x, y, w, h, bg);
+ client->GotFillRect(client, x, y, w, h, bg);
if (subencoding & rfbHextileForegroundSpecified)
if (!ReadFromRFBServer(client, (char *)&fg, sizeof(fg)))
@@ -100,7 +100,7 @@ HandleHextileBPP (rfbClient* client, int rx, int ry, int rw, int rh)
sh = rfbHextileExtractH(*ptr);
ptr++;
- FillRectangle(client, x+sx, y+sy, sw, sh, fg);
+ client->GotFillRect(client, x+sx, y+sy, sw, sh, fg);
}
} else {
@@ -115,7 +115,7 @@ HandleHextileBPP (rfbClient* client, int rx, int ry, int rw, int rh)
sh = rfbHextileExtractH(*ptr);
ptr++;
- FillRectangle(client, x+sx, y+sy, sw, sh, fg);
+ client->GotFillRect(client, x+sx, y+sy, sw, sh, fg);
}
}
}
diff --git a/libvncclient/listen.c b/libvncclient/listen.c
index 8674b3f..4ecedff 100644
--- a/libvncclient/listen.c
+++ b/libvncclient/listen.c
@@ -89,7 +89,7 @@ listenForIncomingConnections(rfbClient* client)
int r;
/* reap any zombies */
int status, pid;
- while ((pid= wait3(&status, WNOHANG, (struct rusage *)0))>0);
+ while ((pid= wait4(-1, &status, WNOHANG, (struct rusage *)0))>0);
/* TODO: callback for discard any events (like X11 events) */
diff --git a/libvncclient/rfbproto.c b/libvncclient/rfbproto.c
index 4ff1d3b..e099f1a 100644
--- a/libvncclient/rfbproto.c
+++ b/libvncclient/rfbproto.c
@@ -145,125 +145,6 @@ void* rfbClientGetClientData(rfbClient* client, void* tag)
return NULL;
}
-/* messages */
-
-static rfbBool CheckRect(rfbClient* client, int x, int y, int w, int h) {
- return x + w <= client->width && y + h <= client->height;
-}
-
-static void FillRectangle(rfbClient* client, int x, int y, int w, int h, uint32_t colour) {
- int i,j;
-
- if (client->frameBuffer == NULL) {
- return;
- }
-
- if (!CheckRect(client, x, y, w, h)) {
- rfbClientLog("Rect out of bounds: %dx%d at (%d, %d)\n", x, y, w, h);
- return;
- }
-
-#define FILL_RECT(BPP) \
- for(j=y*client->width;j<(y+h)*client->width;j+=client->width) \
- for(i=x;i<x+w;i++) \
- ((uint##BPP##_t*)client->frameBuffer)[j+i]=colour;
-
- switch(client->format.bitsPerPixel) {
- case 8: FILL_RECT(8); break;
- case 16: FILL_RECT(16); break;
- case 32: FILL_RECT(32); break;
- default:
- rfbClientLog("Unsupported bitsPerPixel: %d\n",client->format.bitsPerPixel);
- }
-}
-
-static void CopyRectangle(rfbClient* client, uint8_t* buffer, int x, int y, int w, int h) {
- int j;
-
- if (client->frameBuffer == NULL) {
- return;
- }
-
- if (!CheckRect(client, x, y, w, h)) {
- rfbClientLog("Rect out of bounds: %dx%d at (%d, %d)\n", x, y, w, h);
- return;
- }
-
-#define COPY_RECT(BPP) \
- { \
- int rs = w * BPP / 8, rs2 = client->width * BPP / 8; \
- for (j = ((x * (BPP / 8)) + (y * rs2)); j < (y + h) * rs2; j += rs2) { \
- memcpy(client->frameBuffer + j, buffer, rs); \
- buffer += rs; \
- } \
- }
-
- switch(client->format.bitsPerPixel) {
- case 8: COPY_RECT(8); break;
- case 16: COPY_RECT(16); break;
- case 32: COPY_RECT(32); break;
- default:
- rfbClientLog("Unsupported bitsPerPixel: %d\n",client->format.bitsPerPixel);
- }
-}
-
-/* TODO: test */
-static void CopyRectangleFromRectangle(rfbClient* client, int src_x, int src_y, int w, int h, int dest_x, int dest_y) {
- int i,j;
-
- if (client->frameBuffer == NULL) {
- return;
- }
-
- if (!CheckRect(client, src_x, src_y, w, h)) {
- rfbClientLog("Source rect out of bounds: %dx%d at (%d, %d)\n", src_x, src_y, w, h);
- return;
- }
-
- if (!CheckRect(client, dest_x, dest_y, w, h)) {
- rfbClientLog("Dest rect out of bounds: %dx%d at (%d, %d)\n", dest_x, dest_y, w, h);
- return;
- }
-
-#define COPY_RECT_FROM_RECT(BPP) \
- { \
- uint##BPP##_t* _buffer=((uint##BPP##_t*)client->frameBuffer)+(src_y-dest_y)*client->width+src_x-dest_x; \
- if (dest_y < src_y) { \
- for(j = dest_y*client->width; j < (dest_y+h)*client->width; j += client->width) { \
- if (dest_x < src_x) { \
- for(i = dest_x; i < dest_x+w; i++) { \
- ((uint##BPP##_t*)client->frameBuffer)[j+i]=_buffer[j+i]; \
- } \
- } else { \
- for(i = dest_x+w-1; i >= dest_x; i--) { \
- ((uint##BPP##_t*)client->frameBuffer)[j+i]=_buffer[j+i]; \
- } \
- } \
- } \
- } else { \
- for(j = (dest_y+h-1)*client->width; j >= dest_y*client->width; j-=client->width) { \
- if (dest_x < src_x) { \
- for(i = dest_x; i < dest_x+w; i++) { \
- ((uint##BPP##_t*)client->frameBuffer)[j+i]=_buffer[j+i]; \
- } \
- } else { \
- for(i = dest_x+w-1; i >= dest_x; i--) { \
- ((uint##BPP##_t*)client->frameBuffer)[j+i]=_buffer[j+i]; \
- } \
- } \
- } \
- } \
- }
-
- switch(client->format.bitsPerPixel) {
- case 8: COPY_RECT_FROM_RECT(8); break;
- case 16: COPY_RECT_FROM_RECT(16); break;
- case 32: COPY_RECT_FROM_RECT(32); break;
- default:
- rfbClientLog("Unsupported bitsPerPixel: %d\n",client->format.bitsPerPixel);
- }
-}
-
static rfbBool HandleRRE8(rfbClient* client, int rx, int ry, int rw, int rh);
static rfbBool HandleRRE16(rfbClient* client, int rx, int ry, int rw, int rh);
static rfbBool HandleRRE32(rfbClient* client, int rx, int ry, int rw, int rh);
@@ -1980,7 +1861,7 @@ HandleRFBServerMessage(rfbClient* client)
if (!ReadFromRFBServer(client, client->buffer,bytesPerLine * linesToRead))
return FALSE;
- CopyRectangle(client, (uint8_t *)client->buffer,
+ client->GotBitmap(client, (uint8_t *)client->buffer,
rect.r.x, y, rect.r.w,linesToRead);
h -= linesToRead;
@@ -2006,13 +1887,8 @@ HandleRFBServerMessage(rfbClient* client)
client->SoftCursorLockArea(client,
cr.srcX, cr.srcY, rect.r.w, rect.r.h);
- if (client->GotCopyRect != NULL) {
- client->GotCopyRect(client, cr.srcX, cr.srcY, rect.r.w, rect.r.h,
- rect.r.x, rect.r.y);
- } else
- CopyRectangleFromRectangle(client,
- cr.srcX, cr.srcY, rect.r.w, rect.r.h,
- rect.r.x, rect.r.y);
+ client->GotCopyRect(client, cr.srcX, cr.srcY, rect.r.w, rect.r.h,
+ rect.r.x, rect.r.y);
break;
}
diff --git a/libvncclient/rre.c b/libvncclient/rre.c
index 94158c9..752d7cc 100644
--- a/libvncclient/rre.c
+++ b/libvncclient/rre.c
@@ -45,7 +45,7 @@ HandleRREBPP (rfbClient* client, int rx, int ry, int rw, int rh)
if (!ReadFromRFBServer(client, (char *)&pix, sizeof(pix)))
return FALSE;
- FillRectangle(client, rx, ry, rw, rh, pix);
+ client->GotFillRect(client, rx, ry, rw, rh, pix);
for (i = 0; i < hdr.nSubrects; i++) {
if (!ReadFromRFBServer(client, (char *)&pix, sizeof(pix)))
@@ -59,7 +59,7 @@ HandleRREBPP (rfbClient* client, int rx, int ry, int rw, int rh)
subrect.w = rfbClientSwap16IfLE(subrect.w);
subrect.h = rfbClientSwap16IfLE(subrect.h);
- FillRectangle(client, rx+subrect.x, ry+subrect.y, subrect.w, subrect.h, pix);
+ client->GotFillRect(client, rx+subrect.x, ry+subrect.y, subrect.w, subrect.h, pix);
}
return TRUE;
diff --git a/libvncclient/tight.c b/libvncclient/tight.c
index 2f9fbab..2447ad8 100644
--- a/libvncclient/tight.c
+++ b/libvncclient/tight.c
@@ -131,7 +131,7 @@ HandleTightBPP (rfbClient* client, int rx, int ry, int rw, int rh)
return FALSE;
#endif
- FillRectangle(client, rx, ry, rw, rh, fill_colour);
+ client->GotFillRect(client, rx, ry, rw, rh, fill_colour);
return TRUE;
}
@@ -198,7 +198,7 @@ HandleTightBPP (rfbClient* client, int rx, int ry, int rw, int rh)
buffer2 = &client->buffer[TIGHT_MIN_TO_COMPRESS * 4];
filterFn(client, rh, (CARDBPP *)buffer2);
- CopyRectangle(client, (uint8_t *)buffer2, rx, ry, rw, rh);
+ client->GotBitmap(client, (uint8_t *)buffer2, rx, ry, rw, rh);
return TRUE;
}
@@ -277,7 +277,7 @@ HandleTightBPP (rfbClient* client, int rx, int ry, int rw, int rh)
if (extraBytes > 0)
memcpy(client->buffer, &client->buffer[numRows * rowSize], extraBytes);
- CopyRectangle(client, (uint8_t *)buffer2, rx, ry+rowsProcessed, rw, numRows);
+ client->GotBitmap(client, (uint8_t *)buffer2, rx, ry+rowsProcessed, rw, numRows);
rowsProcessed += numRows;
}
@@ -547,6 +547,9 @@ DecompressJpegRectBPP(rfbClient* client, int x, int y, int w, int h)
return FALSE;
}
+ if(client->GotJpeg != NULL)
+ return client->GotJpeg(client, compressedData, compressedLen, x, y, w, h);
+
cinfo.err = jpeg_std_error(&jerr);
cinfo.client_data = client;
jpeg_create_decompress(&cinfo);
@@ -577,7 +580,7 @@ DecompressJpegRectBPP(rfbClient* client, int x, int y, int w, int h)
*pixelPtr++ =
RGB24_TO_PIXEL(BPP, client->buffer[dx*3], client->buffer[dx*3+1], client->buffer[dx*3+2]);
}
- CopyRectangle(client, (uint8_t *)&client->buffer[RFB_BUFFER_SIZE / 2], x, y + dy, w, 1);
+ client->GotBitmap(client, (uint8_t *)&client->buffer[RFB_BUFFER_SIZE / 2], x, y + dy, w, 1);
dy++;
}
diff --git a/libvncclient/tls_gnutls.c b/libvncclient/tls_gnutls.c
index b9ffe89..f49fa85 100644
--- a/libvncclient/tls_gnutls.c
+++ b/libvncclient/tls_gnutls.c
@@ -18,6 +18,7 @@
*/
#include <gnutls/gnutls.h>
+#include <gnutls/x509.h>
#include <rfb/rfbclient.h>
#include <errno.h>
#ifdef WIN32
@@ -39,6 +40,98 @@ static gnutls_dh_params_t rfbDHParams;
static rfbBool rfbTLSInitialized = FALSE;
+static int
+verify_certificate_callback (gnutls_session_t session)
+{
+ unsigned int status;
+ const gnutls_datum_t *cert_list;
+ unsigned int cert_list_size;
+ int ret;
+ gnutls_x509_crt_t cert;
+ rfbClient *sptr;
+ char *hostname;
+
+ sptr = (rfbClient *)gnutls_session_get_ptr(session);
+ if (!sptr) {
+ rfbClientLog("Failed to validate certificate - missing client data\n");
+ return GNUTLS_E_CERTIFICATE_ERROR;
+ }
+
+ hostname = sptr->serverHost;
+ if (!hostname) {
+ rfbClientLog("No server hostname found for client\n");
+ return GNUTLS_E_CERTIFICATE_ERROR;
+ }
+
+ /* This verification function uses the trusted CAs in the credentials
+ * structure. So you must have installed one or more CA certificates.
+ */
+ ret = gnutls_certificate_verify_peers2 (session, &status);
+ if (ret < 0)
+ {
+ rfbClientLog ("Certificate validation call failed\n");
+ return GNUTLS_E_CERTIFICATE_ERROR;
+ }
+
+ if (status & GNUTLS_CERT_INVALID)
+ rfbClientLog("The certificate is not trusted.\n");
+
+ if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
+ rfbClientLog("The certificate hasn't got a known issuer.\n");
+
+ if (status & GNUTLS_CERT_REVOKED)
+ rfbClientLog("The certificate has been revoked.\n");
+
+ if (status & GNUTLS_CERT_EXPIRED)
+ rfbClientLog("The certificate has expired\n");
+
+ if (status & GNUTLS_CERT_NOT_ACTIVATED)
+ rfbClientLog("The certificate is not yet activated\n");
+
+ if (status)
+ return GNUTLS_E_CERTIFICATE_ERROR;
+
+ /* Up to here the process is the same for X.509 certificates and
+ * OpenPGP keys. From now on X.509 certificates are assumed. This can
+ * be easily extended to work with openpgp keys as well.
+ */
+ if (gnutls_certificate_type_get (session) != GNUTLS_CRT_X509) {
+ rfbClientLog("The certificate was not X509\n");
+ return GNUTLS_E_CERTIFICATE_ERROR;
+ }
+
+ if (gnutls_x509_crt_init (&cert) < 0)
+ {
+ rfbClientLog("Error initialising certificate structure\n");
+ return GNUTLS_E_CERTIFICATE_ERROR;
+ }
+
+ cert_list = gnutls_certificate_get_peers (session, &cert_list_size);
+ if (cert_list == NULL)
+ {
+ rfbClientLog("No certificate was found!\n");
+ return GNUTLS_E_CERTIFICATE_ERROR;
+ }
+
+ if (gnutls_x509_crt_import (cert, &cert_list[0], GNUTLS_X509_FMT_DER) < 0)
+ {
+ rfbClientLog("Error parsing certificate\n");
+ return GNUTLS_E_CERTIFICATE_ERROR;
+ }
+
+ if (!gnutls_x509_crt_check_hostname (cert, hostname))
+ {
+ rfbClientLog("The certificate's owner does not match hostname '%s'\n",
+ hostname);
+ return GNUTLS_E_CERTIFICATE_ERROR;
+ }
+
+ gnutls_x509_crt_deinit (cert);
+
+ /* notify gnutls to continue handshake normally */
+ return 0;
+}
+
static rfbBool
InitializeTLS(void)
{
@@ -52,7 +145,7 @@ InitializeTLS(void)
rfbClientLog("Failed to initialized GnuTLS: %s.\n", gnutls_strerror(ret));
return FALSE;
}
- rfbClientLog("GnuTLS initialized.\n");
+ rfbClientLog("GnuTLS version %s initialized.\n", gnutls_check_version(NULL));
rfbTLSInitialized = TRUE;
return TRUE;
}
@@ -170,7 +263,7 @@ InitializeTLSSession(rfbClient* client, rfbBool anonTLS)
static rfbBool
SetTLSAnonCredential(rfbClient* client)
{
- gnutls_anon_client_credentials anonCred;
+ gnutls_anon_client_credentials_t anonCred;
int ret;
if ((ret = gnutls_anon_allocate_client_credentials(&anonCred)) < 0 ||
@@ -200,6 +293,7 @@ HandshakeTLS(rfbClient* client)
continue;
}
rfbClientLog("TLS handshake failed: %s.\n", gnutls_strerror(ret));
+
FreeTLS(client);
return FALSE;
}
@@ -449,6 +543,10 @@ HandleVeNCryptAuth(rfbClient* client)
}
else
{
+ /* Set the certificate verification callback. */
+ gnutls_certificate_set_verify_function (x509_cred, verify_certificate_callback);
+ gnutls_session_set_ptr ((gnutls_session_t)client->tlsSession, (void *)client);
+
if ((ret = gnutls_credentials_set((gnutls_session_t)client->tlsSession, GNUTLS_CRD_CERTIFICATE, x509_cred)) < 0)
{
rfbClientLog("Cannot set x509 credential: %s.\n", gnutls_strerror(ret));
@@ -459,8 +557,6 @@ HandleVeNCryptAuth(rfbClient* client)
if (!HandshakeTLS(client)) return FALSE;
- /* TODO: validate certificate */
-
/* We are done here. The caller should continue with client->subAuthScheme
* to do actual sub authentication.
*/
diff --git a/libvncclient/tls_openssl.c b/libvncclient/tls_openssl.c
index 1b6c986..2bdf3eb 100644
--- a/libvncclient/tls_openssl.c
+++ b/libvncclient/tls_openssl.c
@@ -168,53 +168,11 @@ InitializeTLS(void)
SSLeay_add_ssl_algorithms();
RAND_load_file("/dev/urandom", 1024);
- rfbClientLog("OpenSSL initialized.\n");
+ rfbClientLog("OpenSSL version %s initialized.\n", SSLeay_version(SSLEAY_VERSION));
rfbTLSInitialized = TRUE;
return TRUE;
}
-static int
-ssl_verify (int ok, X509_STORE_CTX *ctx)
-{
- unsigned char md5sum[16], fingerprint[40], *f;
- rfbClient *client;
- int err, i;
- unsigned int md5len;
- //char buf[257];
- X509 *cert;
- SSL *ssl;
-
- if (ok)
- return TRUE;
-
- ssl = X509_STORE_CTX_get_ex_data (ctx, SSL_get_ex_data_X509_STORE_CTX_idx ());
-
- client = SSL_CTX_get_app_data (SSL_get_SSL_CTX(ssl));
-
- cert = X509_STORE_CTX_get_current_cert (ctx);
- err = X509_STORE_CTX_get_error (ctx);
-
- /* calculate the MD5 hash of the raw certificate */
- md5len = sizeof (md5sum);
- X509_digest (cert, EVP_md5 (), md5sum, &md5len);
- for (i = 0, f = fingerprint; i < 16; i++, f += 3)
- sprintf ((char *) f, "%.2x%c", md5sum[i], i != 15 ? ':' : '\0');
-
-#define GET_STRING(name) X509_NAME_oneline (name, buf, 256)
-
- /* TODO: Don't just ignore certificate checks
-
- fingerprint = key to check in db
-
- GET_STRING (X509_get_issuer_name (cert));
- GET_STRING (X509_get_subject_name (cert));
- cert->valid (bool: GOOD or BAD) */
-
- ok = TRUE;
-
- return ok;
-}
-
static int sock_read_ready(SSL *ssl, uint32_t ms)
{
int r = 0;
@@ -251,8 +209,12 @@ static int wait_for_data(SSL *ssl, int ret, int timeout)
}
break;
- default:
+ default:
retval = 3;
+ long verify_res = SSL_get_verify_result(ssl);
+ if (verify_res != X509_V_OK)
+ rfbClientLog("Could not verify server certificate: %s.\n",
+ X509_verify_cert_error_string(verify_res));
break;
}
@@ -261,17 +223,131 @@ static int wait_for_data(SSL *ssl, int ret, int timeout)
return retval;
}
+static rfbBool
+load_crls_from_file(char *file, SSL_CTX *ssl_ctx)
+{
+ X509_STORE *st;
+ X509_CRL *crl;
+ int i;
+ int count = 0;
+ BIO *bio;
+ STACK_OF(X509_INFO) *xis = NULL;
+ X509_INFO *xi;
+
+ st = SSL_CTX_get_cert_store(ssl_ctx);
+
+ int rv = 0;
+
+ bio = BIO_new_file(file, "r");
+ if (bio == NULL)
+ return FALSE;
+
+ xis = PEM_X509_INFO_read_bio(bio, NULL, NULL, NULL);
+ BIO_free(bio);
+
+ for (i = 0; i < sk_X509_INFO_num(xis); i++)
+ {
+ xi = sk_X509_INFO_value(xis, i);
+ if (xi->crl)
+ {
+ X509_STORE_add_crl(st, xi->crl);
+ xi->crl = NULL;
+ count++;
+ }
+ }
+
+ sk_X509_INFO_pop_free(xis, X509_INFO_free);
+
+ if (count > 0)
+ return TRUE;
+ else
+ return FALSE;
+}
+
static SSL *
-open_ssl_connection (rfbClient *client, int sockfd, rfbBool anonTLS)
+open_ssl_connection (rfbClient *client, int sockfd, rfbBool anonTLS, rfbCredential *cred)
{
SSL_CTX *ssl_ctx = NULL;
SSL *ssl = NULL;
int n, finished = 0;
+ X509_VERIFY_PARAM *param;
+ uint8_t verify_crls = cred->x509Credential.x509CrlVerifyMode;
- ssl_ctx = SSL_CTX_new (SSLv23_client_method ());
- SSL_CTX_set_default_verify_paths (ssl_ctx);
- SSL_CTX_set_verify (ssl_ctx, SSL_VERIFY_NONE, &ssl_verify);
- ssl = SSL_new (ssl_ctx);
+ if (!(ssl_ctx = SSL_CTX_new(SSLv23_client_method())))
+ {
+ rfbClientLog("Could not create new SSL context.\n");
+ return NULL;
+ }
+
+ param = X509_VERIFY_PARAM_new();
+
+ /* Setup verification if not anonymous */
+ if (!anonTLS)
+ {
+ if (cred->x509Credential.x509CACertFile)
+ {
+ if (!SSL_CTX_load_verify_locations(ssl_ctx, cred->x509Credential.x509CACertFile, NULL))
+ {
+ rfbClientLog("Failed to load CA certificate from %s.\n",
+ cred->x509Credential.x509CACertFile);
+ goto error_free_ctx;
+ }
+ } else {
+ rfbClientLog("Using default paths for certificate verification.\n");
+ SSL_CTX_set_default_verify_paths (ssl_ctx);
+ }
+
+ if (cred->x509Credential.x509CACrlFile)
+ {
+ if (!load_crls_from_file(cred->x509Credential.x509CACrlFile, ssl_ctx))
+ {
+ rfbClientLog("CRLs could not be loaded.\n");
+ goto error_free_ctx;
+ }
+ if (verify_crls == rfbX509CrlVerifyNone) verify_crls = rfbX509CrlVerifyAll;
+ }
+
+ if (cred->x509Credential.x509ClientCertFile && cred->x509Credential.x509ClientKeyFile)
+ {
+ if (SSL_CTX_use_certificate_chain_file(ssl_ctx, cred->x509Credential.x509ClientCertFile) != 1)
+ {
+ rfbClientLog("Client certificate could not be loaded.\n");
+ goto error_free_ctx;
+ }
+
+ if (SSL_CTX_use_PrivateKey_file(ssl_ctx, cred->x509Credential.x509ClientKeyFile,
+ SSL_FILETYPE_PEM) != 1)
+ {
+ rfbClientLog("Client private key could not be loaded.\n");
+ goto error_free_ctx;
+ }
+
+ if (SSL_CTX_check_private_key(ssl_ctx) == 0) {
+ rfbClientLog("Client certificate and private key do not match.\n");
+ goto error_free_ctx;
+ }
+ }
+
+ SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_PEER, NULL);
+
+ if (verify_crls == rfbX509CrlVerifyClient)
+ X509_VERIFY_PARAM_set_flags(param, X509_V_FLAG_CRL_CHECK);
+ else if (verify_crls == rfbX509CrlVerifyAll)
+ X509_VERIFY_PARAM_set_flags(param, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL);
+
+ if(!X509_VERIFY_PARAM_set1_host(param, client->serverHost, strlen(client->serverHost)))
+ {
+ rfbClientLog("Could not set server name for verification.\n");
+ goto error_free_ctx;
+ }
+ SSL_CTX_set1_param(ssl_ctx, param);
+ }
+
+ if (!(ssl = SSL_new (ssl_ctx)))
+ {
+ rfbClientLog("Could not create a new SSL session.\n");
+ goto error_free_ctx;
+ }
/* TODO: finetune this list, take into account anonTLS bool */
SSL_set_cipher_list(ssl, "ALL");
@@ -289,24 +365,32 @@ open_ssl_connection (rfbClient *client, int sockfd, rfbBool anonTLS)
{
finished = 1;
SSL_shutdown(ssl);
- SSL_free(ssl);
- SSL_CTX_free(ssl_ctx);
- return NULL;
+ goto error_free_ssl;
}
}
} while( n != 1 && finished != 1 );
+ X509_VERIFY_PARAM_free(param);
return ssl;
+
+error_free_ssl:
+ SSL_free(ssl);
+
+error_free_ctx:
+ X509_VERIFY_PARAM_free(param);
+ SSL_CTX_free(ssl_ctx);
+
+ return NULL;
}
static rfbBool
-InitializeTLSSession(rfbClient* client, rfbBool anonTLS)
+InitializeTLSSession(rfbClient* client, rfbBool anonTLS, rfbCredential *cred)
{
if (client->tlsSession) return TRUE;
- client->tlsSession = open_ssl_connection (client, client->sock, anonTLS);
+ client->tlsSession = open_ssl_connection (client, client->sock, anonTLS, cred);
if (!client->tlsSession)
return FALSE;
@@ -317,13 +401,6 @@ InitializeTLSSession(rfbClient* client, rfbBool anonTLS)
}
static rfbBool
-SetTLSAnonCredential(rfbClient* client)
-{
- rfbClientLog("TLS anonymous credential created.\n");
- return TRUE;
-}
-
-static rfbBool
HandshakeTLS(rfbClient* client)
{
int timeout = 15;
@@ -344,7 +421,8 @@ return TRUE;
timeout--;
continue;
}
- rfbClientLog("TLS handshake failed: -.\n");
+ rfbClientLog("TLS handshake failed.\n");
+
FreeTLS(client);
return FALSE;
}
@@ -429,22 +507,31 @@ ReadVeNCryptSecurityType(rfbClient* client, uint32_t *result)
rfbBool
HandleAnonTLSAuth(rfbClient* client)
{
- if (!InitializeTLS() || !InitializeTLSSession(client, TRUE)) return FALSE;
-
- if (!SetTLSAnonCredential(client)) return FALSE;
+ if (!InitializeTLS() || !InitializeTLSSession(client, TRUE, NULL)) return FALSE;
if (!HandshakeTLS(client)) return FALSE;
return TRUE;
}
+static void
+FreeX509Credential(rfbCredential *cred)
+{
+ if (cred->x509Credential.x509CACertFile) free(cred->x509Credential.x509CACertFile);
+ if (cred->x509Credential.x509CACrlFile) free(cred->x509Credential.x509CACrlFile);
+ if (cred->x509Credential.x509ClientCertFile) free(cred->x509Credential.x509ClientCertFile);
+ if (cred->x509Credential.x509ClientKeyFile) free(cred->x509Credential.x509ClientKeyFile);
+ free(cred);
+}
+
rfbBool
HandleVeNCryptAuth(rfbClient* client)
{
uint8_t major, minor, status;
uint32_t authScheme;
rfbBool anonTLS;
-// gnutls_certificate_credentials_t x509_cred = NULL;
+ rfbCredential *cred = NULL;
+ rfbBool result = TRUE;
if (!InitializeTLS()) return FALSE;
@@ -499,7 +586,6 @@ HandleVeNCryptAuth(rfbClient* client)
/* Get X509 Credentials if it's not anonymous */
if (!anonTLS)
{
- rfbCredential *cred;
if (!client->GetCredential)
{
@@ -512,39 +598,18 @@ HandleVeNCryptAuth(rfbClient* client)
rfbClientLog("Reading credential failed\n");
return FALSE;
}
-
- /* TODO: don't just ignore this
- x509_cred = CreateX509CertCredential(cred);
- FreeX509Credential(cred);
- if (!x509_cred) return FALSE; */
}
/* Start up the TLS session */
- if (!InitializeTLSSession(client, anonTLS)) return FALSE;
+ if (!InitializeTLSSession(client, anonTLS, cred)) result = FALSE;
- if (anonTLS)
- {
- if (!SetTLSAnonCredential(client)) return FALSE;
- }
- else
- {
-/* TODO: don't just ignore this
- if ((ret = gnutls_credentials_set(client->tlsSession, GNUTLS_CRD_CERTIFICATE, x509_cred)) < 0)
- {
- rfbClientLog("Cannot set x509 credential: %s.\n", gnutls_strerror(ret));
- FreeTLS(client); */
- return FALSE;
- // }
- }
-
- if (!HandshakeTLS(client)) return FALSE;
-
- /* TODO: validate certificate */
+ if (!HandshakeTLS(client)) result = FALSE;
/* We are done here. The caller should continue with client->subAuthScheme
* to do actual sub authentication.
*/
- return TRUE;
+ if (cred) FreeX509Credential(cred);
+ return result;
}
int
diff --git a/libvncclient/ultra.c b/libvncclient/ultra.c
index 32a1b2b..a82e2ed 100644
--- a/libvncclient/ultra.c
+++ b/libvncclient/ultra.c
@@ -98,7 +98,7 @@ HandleUltraBPP (rfbClient* client, int rx, int ry, int rw, int rh)
/* Put the uncompressed contents of the update on the screen. */
if ( inflateResult == LZO_E_OK )
{
- CopyRectangle(client, (unsigned char *)client->raw_buffer, rx, ry, rw, rh);
+ client->GotBitmap(client, (unsigned char *)client->raw_buffer, rx, ry, rw, rh);
}
else
{
@@ -199,7 +199,7 @@ HandleUltraZipBPP (rfbClient* client, int rx, int ry, int rw, int rh)
if (se == rfbEncodingRaw)
{
- CopyRectangle(client, (unsigned char *)ptr, sx, sy, sw, sh);
+ client->GotBitmap(client, (unsigned char *)ptr, sx, sy, sw, sh);
ptr += ((sw * sh) * (BPP / 8));
}
}
diff --git a/libvncclient/vncviewer.c b/libvncclient/vncviewer.c
index d81e298..780a1cb 100644
--- a/libvncclient/vncviewer.c
+++ b/libvncclient/vncviewer.c
@@ -113,6 +113,125 @@ static rfbBool MallocFrameBuffer(rfbClient* client) {
return client->frameBuffer?TRUE:FALSE;
}
+/* messages */
+
+static rfbBool CheckRect(rfbClient* client, int x, int y, int w, int h) {
+ return x + w <= client->width && y + h <= client->height;
+}
+
+static void FillRectangle(rfbClient* client, int x, int y, int w, int h, uint32_t colour) {
+ int i,j;
+
+ if (client->frameBuffer == NULL) {
+ return;
+ }
+
+ if (!CheckRect(client, x, y, w, h)) {
+ rfbClientLog("Rect out of bounds: %dx%d at (%d, %d)\n", x, y, w, h);
+ return;
+ }
+
+#define FILL_RECT(BPP) \
+ for(j=y*client->width;j<(y+h)*client->width;j+=client->width) \
+ for(i=x;i<x+w;i++) \
+ ((uint##BPP##_t*)client->frameBuffer)[j+i]=colour;
+
+ switch(client->format.bitsPerPixel) {
+ case 8: FILL_RECT(8); break;
+ case 16: FILL_RECT(16); break;
+ case 32: FILL_RECT(32); break;
+ default:
+ rfbClientLog("Unsupported bitsPerPixel: %d\n",client->format.bitsPerPixel);
+ }
+}
+
+static void CopyRectangle(rfbClient* client, const uint8_t* buffer, int x, int y, int w, int h) {
+ int j;
+
+ if (client->frameBuffer == NULL) {
+ return;
+ }
+
+ if (!CheckRect(client, x, y, w, h)) {
+ rfbClientLog("Rect out of bounds: %dx%d at (%d, %d)\n", x, y, w, h);
+ return;
+ }
+
+#define COPY_RECT(BPP) \
+ { \
+ int rs = w * BPP / 8, rs2 = client->width * BPP / 8; \
+ for (j = ((x * (BPP / 8)) + (y * rs2)); j < (y + h) * rs2; j += rs2) { \
+ memcpy(client->frameBuffer + j, buffer, rs); \
+ buffer += rs; \
+ } \
+ }
+
+ switch(client->format.bitsPerPixel) {
+ case 8: COPY_RECT(8); break;
+ case 16: COPY_RECT(16); break;
+ case 32: COPY_RECT(32); break;
+ default:
+ rfbClientLog("Unsupported bitsPerPixel: %d\n",client->format.bitsPerPixel);
+ }
+}
+
+/* TODO: test */
+static void CopyRectangleFromRectangle(rfbClient* client, int src_x, int src_y, int w, int h, int dest_x, int dest_y) {
+ int i,j;
+
+ if (client->frameBuffer == NULL) {
+ return;
+ }
+
+ if (!CheckRect(client, src_x, src_y, w, h)) {
+ rfbClientLog("Source rect out of bounds: %dx%d at (%d, %d)\n", src_x, src_y, w, h);
+ return;
+ }
+
+ if (!CheckRect(client, dest_x, dest_y, w, h)) {
+ rfbClientLog("Dest rect out of bounds: %dx%d at (%d, %d)\n", dest_x, dest_y, w, h);
+ return;
+ }
+
+#define COPY_RECT_FROM_RECT(BPP) \
+ { \
+ uint##BPP##_t* _buffer=((uint##BPP##_t*)client->frameBuffer)+(src_y-dest_y)*client->width+src_x-dest_x; \
+ if (dest_y < src_y) { \
+ for(j = dest_y*client->width; j < (dest_y+h)*client->width; j += client->width) { \
+ if (dest_x < src_x) { \
+ for(i = dest_x; i < dest_x+w; i++) { \
+ ((uint##BPP##_t*)client->frameBuffer)[j+i]=_buffer[j+i]; \
+ } \
+ } else { \
+ for(i = dest_x+w-1; i >= dest_x; i--) { \
+ ((uint##BPP##_t*)client->frameBuffer)[j+i]=_buffer[j+i]; \
+ } \
+ } \
+ } \
+ } else { \
+ for(j = (dest_y+h-1)*client->width; j >= dest_y*client->width; j-=client->width) { \
+ if (dest_x < src_x) { \
+ for(i = dest_x; i < dest_x+w; i++) { \
+ ((uint##BPP##_t*)client->frameBuffer)[j+i]=_buffer[j+i]; \
+ } \
+ } else { \
+ for(i = dest_x+w-1; i >= dest_x; i--) { \
+ ((uint##BPP##_t*)client->frameBuffer)[j+i]=_buffer[j+i]; \
+ } \
+ } \
+ } \
+ } \
+ }
+
+ switch(client->format.bitsPerPixel) {
+ case 8: COPY_RECT_FROM_RECT(8); break;
+ case 16: COPY_RECT_FROM_RECT(16); break;
+ case 32: COPY_RECT_FROM_RECT(32); break;
+ default:
+ rfbClientLog("Unsupported bitsPerPixel: %d\n",client->format.bitsPerPixel);
+ }
+}
+
static void initAppData(AppData* data) {
data->shareDesktop=TRUE;
data->viewOnly=FALSE;
@@ -161,7 +280,7 @@ rfbClient* rfbGetClient(int bitsPerSample,int samplesPerPixel,
client->format.depth = bitsPerSample*samplesPerPixel;
client->appData.requestedDepth=client->format.depth;
client->format.bigEndian = *(char *)&client->endianTest?FALSE:TRUE;
- client->format.trueColour = TRUE;
+ client->format.trueColour = 1;
if (client->format.bitsPerPixel == 8) {
client->format.redMax = 7;
@@ -208,6 +327,9 @@ rfbClient* rfbGetClient(int bitsPerSample,int samplesPerPixel,
client->SoftCursorLockArea = DummyRect;
client->SoftCursorUnlockScreen = Dummy;
client->GotFrameBufferUpdate = DummyRect;
+ client->GotCopyRect = CopyRectangleFromRectangle;
+ client->GotFillRect = FillRectangle;
+ client->GotBitmap = CopyRectangle;
client->FinishedFrameBufferUpdate = NULL;
client->GetPassword = ReadPassword;
client->MallocFrameBuffer = MallocFrameBuffer;
diff --git a/libvncclient/zlib.c b/libvncclient/zlib.c
index e872d40..fc6f138 100644
--- a/libvncclient/zlib.c
+++ b/libvncclient/zlib.c
@@ -142,7 +142,7 @@ HandleZlibBPP (rfbClient* client, int rx, int ry, int rw, int rh)
if ( inflateResult == Z_OK ) {
/* Put the uncompressed contents of the update on the screen. */
- CopyRectangle(client, (uint8_t *)client->raw_buffer, rx, ry, rw, rh);
+ client->GotBitmap(client, (uint8_t *)client->raw_buffer, rx, ry, rw, rh);
}
else {
diff --git a/libvncclient/zrle.c b/libvncclient/zrle.c
index 0128146..e732046 100644
--- a/libvncclient/zrle.c
+++ b/libvncclient/zrle.c
@@ -278,7 +278,7 @@ static int HandleZRLETile(rfbClient* client,
for(i=x; i<x+w; i++,buffer+=REALBPP/8)
((CARDBPP*)client->frameBuffer)[j+i] = UncompressCPixel(buffer);
#else
- CopyRectangle(client, buffer, x, y, w, h);
+ client->GotBitmap(client, buffer, x, y, w, h);
buffer+=w*h*REALBPP/8;
#endif
}
@@ -289,7 +289,7 @@ static int HandleZRLETile(rfbClient* client,
if(1+REALBPP/8>buffer_length)
return -4;
- FillRectangle(client, x, y, w, h, color);
+ client->GotFillRect(client, x, y, w, h, color);
buffer+=REALBPP/8;