diff --git a/src/protocols/vnc/vnc.c b/src/protocols/vnc/vnc.c index d9f9dbbb..d13826d1 100644 --- a/src/protocols/vnc/vnc.c +++ b/src/protocols/vnc/vnc.c @@ -55,6 +55,62 @@ char* GUAC_VNC_CLIENT_KEY = "GUAC_VNC"; +/** + * A callback function that is called by the VNC library prior to writing + * data to a TLS-encrypted socket. This returns the rfbBool FALSE value + * if there's an error locking the mutex, or rfbBool TRUE otherwise. + * + * @param rfb_client + * The rfbClient for which to lock the TLS mutex. + * + * @returns + * rfbBool FALSE if an error occurs locking the mutex, otherwise + * TRUE. + */ +static rfbBool guac_vnc_lock_write_to_tls(rfbClient* rfb_client) { + + // Retrieve the Guacamole data structures + guac_client* gc = rfbClientGetClientData(rfb_client, GUAC_VNC_CLIENT_KEY); + guac_vnc_client* vnc_client = (guac_vnc_client*) gc->data; + + // Lock write access + int retval = pthread_mutex_lock(&(vnc_client->tls_lock)); + if (retval) { + guac_client_log(gc, GUAC_LOG_ERROR, "Error locking TLS write mutex: %d", retval); + return FALSE; + } + return TRUE; + +} + +/** + * A callback function for use by the VNC library that is called once + * the client is finished writing to a TLS-encrypted socket. A rfbBool + * FALSE value is returned if an error occurs unlocking the mutex, + * otherwise TRUE is returned. + * + * @param rfb_client + * The rfbClient for which to unlock the TLS mutex. + * + * @returns + * rfbBool FALSE if an error occurs unlocking the mutex, otherwise + * TRUE. + */ +static rfbBool guac_vnc_unlock_write_to_tls(rfbClient* rfb_client) { + + // Retrieve the Guacamole data structures + guac_client* gc = rfbClientGetClientData(rfb_client, GUAC_VNC_CLIENT_KEY); + guac_vnc_client* vnc_client = (guac_vnc_client*) gc->data; + + // Unlock write access + int retval = pthread_mutex_unlock(&(vnc_client->tls_lock)); + if (retval) { + guac_client_log(gc, GUAC_LOG_ERROR, "Error unlocking TLS write mutex: %d", retval); + return FALSE; + } + return TRUE; +} + rfbClient* guac_vnc_get_client(guac_client* client) { rfbClient* rfb_client = rfbGetClient(8, 3, 4); /* 32-bpp client */ @@ -68,6 +124,10 @@ rfbClient* guac_vnc_get_client(guac_client* client) { rfb_client->GotFrameBufferUpdate = guac_vnc_update; rfb_client->GotCopyRect = guac_vnc_copyrect; + /* TLS Locking and Unlocking */ + rfb_client->LockWriteToTLS = guac_vnc_lock_write_to_tls; + rfb_client->UnlockWriteToTLS = guac_vnc_unlock_write_to_tls; + /* Do not handle clipboard and local cursor if read-only */ if (vnc_settings->read_only == 0) { @@ -182,6 +242,9 @@ void* guac_vnc_client_thread(void* data) { rfbClientLog = guac_vnc_client_log_info; rfbClientErr = guac_vnc_client_log_error; + /* Initialize the write lock */ + pthread_mutex_init(&(vnc_client->tls_lock), NULL); + /* Attempt connection */ rfbClient* rfb_client = guac_vnc_get_client(client); int retries_remaining = settings->retries; @@ -403,4 +466,3 @@ void* guac_vnc_client_thread(void* data) { return NULL; } - diff --git a/src/protocols/vnc/vnc.h b/src/protocols/vnc/vnc.h index ce2d20af..31e78461 100644 --- a/src/protocols/vnc/vnc.h +++ b/src/protocols/vnc/vnc.h @@ -55,6 +55,11 @@ typedef struct guac_vnc_client { */ pthread_t client_thread; + /** + * The TLS mutex lock for the client. + */ + pthread_mutex_t tls_lock; + /** * The underlying VNC client. */