diff options
Diffstat (limited to 'libvncclient')
-rw-r--r-- | libvncclient/Makefile.am | 29 | ||||
-rw-r--r-- | libvncclient/corre.c | 4 | ||||
-rw-r--r-- | libvncclient/hextile.c | 8 | ||||
-rw-r--r-- | libvncclient/listen.c | 2 | ||||
-rw-r--r-- | libvncclient/rfbproto.c | 130 | ||||
-rw-r--r-- | libvncclient/rre.c | 4 | ||||
-rw-r--r-- | libvncclient/tight.c | 11 | ||||
-rw-r--r-- | libvncclient/tls_gnutls.c | 104 | ||||
-rw-r--r-- | libvncclient/tls_openssl.c | 249 | ||||
-rw-r--r-- | libvncclient/ultra.c | 4 | ||||
-rw-r--r-- | libvncclient/vncviewer.c | 124 | ||||
-rw-r--r-- | libvncclient/zlib.c | 2 | ||||
-rw-r--r-- | libvncclient/zrle.c | 4 |
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; |