diff --git a/include/common.h b/include/common.h index ed809e6f..18697328 100644 --- a/include/common.h +++ b/include/common.h @@ -138,6 +138,7 @@ struct nvnc_client { #ifdef HAVE_CRYPTO struct crypto_key* apple_dh_secret; + struct crypto_cipher* apple_dh_cipher; struct { enum crypto_hash_type hash_type; diff --git a/include/rfb-proto.h b/include/rfb-proto.h index d0c7b91d..280a76ae 100644 --- a/include/rfb-proto.h +++ b/include/rfb-proto.h @@ -17,6 +17,7 @@ #pragma once #define RFB_VERSION_MESSAGE "RFB 003.008\n" +#define RFB_VERSION_MESSAGE_AAPL "RFB 003.889\n" #include #include @@ -48,6 +49,9 @@ enum rfb_client_to_server_msg_type { RFB_CLIENT_TO_SERVER_KEY_EVENT = 4, RFB_CLIENT_TO_SERVER_POINTER_EVENT = 5, RFB_CLIENT_TO_SERVER_CLIENT_CUT_TEXT = 6, + RFB_CLIENT_TO_SERVER_APPLE_CONTINUOUS_UPDATES = 9, + RFB_CLIENT_TO_SERVER_APPLE_SET_MODE = 10, + RFB_CLIENT_TO_SERVER_APPLE_ENCRYPTED_EVENT_MESSAGE = 16, RFB_CLIENT_TO_SERVER_ENABLE_CONTINUOUS_UPDATES = 150, RFB_CLIENT_TO_SERVER_NTP = 160, RFB_CLIENT_TO_SERVER_FENCE = 248, @@ -363,3 +367,27 @@ struct rfb_fence_msg { uint8_t length; uint8_t payload[0]; } RFB_PACKED; + +struct rfb_apple_enc_event_msg { + uint8_t type; + uint8_t flags; + uint8_t keyboard; + uint8_t down_flag; + uint32_t key; + uint32_t delta; + uint8_t mouse; + uint8_t button_mask; + uint16_t x; + uint16_t y; +} RFB_PACKED; + +struct rfb_apple_continuous_update_msg { + uint8_t type; + uint8_t padding; + uint16_t flag; + uint32_t ms_between_updates; + uint16_t x; + uint16_t y; + uint16_t width; + uint16_t height; +} RFB_PACKED; diff --git a/src/auth/apple-dh.c b/src/auth/apple-dh.c index 6777d89b..f08eb628 100644 --- a/src/auth/apple-dh.c +++ b/src/auth/apple-dh.c @@ -94,18 +94,20 @@ int apple_dh_handle_response(struct nvnc_client* client) msg->encrypted_credentials, sizeof(username), NULL, 0); username[63] = '\0'; username[127] = '\0'; - crypto_cipher_del(cipher); update_min_rtt(client); if (!server->auth_fn(username, password, server->auth_ud)) { security_handshake_failed(client, username, "Invalid username or password"); + client->apple_dh_cipher = NULL; + crypto_cipher_del(cipher); return -1; } security_handshake_ok(client, username); client->state = VNC_CLIENT_STATE_WAITING_FOR_INIT; + client->apple_dh_cipher = cipher; return sizeof(*msg) + key_len; } diff --git a/src/server.c b/src/server.c index f1726584..2a7f8fa5 100644 --- a/src/server.c +++ b/src/server.c @@ -189,6 +189,7 @@ static void client_close(struct nvnc_client* client) bwe_destroy(client->bwe); #ifdef HAVE_CRYPTO + crypto_cipher_del(client->apple_dh_cipher); crypto_key_del(client->apple_dh_secret); crypto_rsa_pub_key_del(client->rsa.pub); #endif @@ -1897,6 +1898,91 @@ static int on_client_fence(struct nvnc_client* client) return sizeof(*msg) + length; } +static int on_apple_client_continuous_updates(struct nvnc_client* client) +{ + struct rfb_apple_continuous_update_msg *msg = + (struct rfb_apple_continuous_update_msg*)( + client->msg_buffer + client->buffer_index); + + if (client->buffer_len - client->buffer_index < sizeof(*msg)) + return 0; + + if(msg->type != RFB_CLIENT_TO_SERVER_APPLE_CONTINUOUS_UPDATES) + return 0; + + if (msg->flag) { + client->continuous_updates_enabled = true; + client->continuous_updates.x = ntohs(msg->x); + client->continuous_updates.y = ntohs(msg->y); + client->continuous_updates.width = ntohs(msg->width); + client->continuous_updates.height = ntohs(msg->height); + + /* If there are any pending messages left, make sure they are processed */ + process_fb_update_requests(client); + } else { + client->continuous_updates_enabled = false; + client->continuous_updates.x = 0; + client->continuous_updates.y = 0; + client->continuous_updates.width = 0; + client->continuous_updates.height = 0; + + nvnc_send_end_of_continuous_updates(client); + } + + return sizeof(*msg); +} + +static int on_apple_client_set_mode(struct nvnc_client* client) +{ + if (client->buffer_len - client->buffer_index < 4) + return 0; + + uint16_t type = ntohs(*(client->msg_buffer + client->buffer_index + 2)); + + return 4; +} + +static int on_apple_client_encrypted_event_message(struct nvnc_client* client) +{ + struct rfb_apple_enc_event_msg *msg = (struct rfb_apple_enc_event_msg *)( + client->msg_buffer + client->buffer_index); + + if (client->buffer_len - client->buffer_index < sizeof(*msg)) + return 0; + + assert(msg->type == RFB_CLIENT_TO_SERVER_APPLE_ENCRYPTED_EVENT_MESSAGE); + + crypto_cipher_decrypt(client->apple_dh_cipher, &msg->keyboard, NULL, + &msg->keyboard, + sizeof(*msg) - offsetof(struct rfb_apple_enc_event_msg, keyboard), + NULL, 0); + + struct nvnc* server = client->server; + + if ((msg->keyboard != 0 && msg->keyboard != 0xff) || + (msg->mouse != 0 && msg->mouse != 0xff)) + return 0; + + if (msg->keyboard == 0xff) { + int down_flag = msg->down_flag; + uint32_t keysym = ntohl(msg->key); + nvnc_key_fn fn = server->key_fn; + if (fn) + fn(client, keysym, !!down_flag); + } + + if (msg->mouse == 0xff) { + int button_mask = msg->button_mask; + uint16_t x = ntohs(msg->x); + uint16_t y = ntohs(msg->y); + nvnc_pointer_fn fn = server->pointer_fn; + if (fn) + fn(client, x, y, button_mask); + } + + return sizeof(*msg); +} + static int on_client_message(struct nvnc_client* client) { if (client->buffer_len - client->buffer_index < 1) @@ -1928,6 +2014,12 @@ static int on_client_message(struct nvnc_client* client) return on_client_ntp(client); case RFB_CLIENT_TO_SERVER_FENCE: return on_client_fence(client); + case RFB_CLIENT_TO_SERVER_APPLE_CONTINUOUS_UPDATES: + return on_apple_client_continuous_updates(client); + case RFB_CLIENT_TO_SERVER_APPLE_SET_MODE: + return on_apple_client_set_mode(client); + case RFB_CLIENT_TO_SERVER_APPLE_ENCRYPTED_EVENT_MESSAGE: + return on_apple_client_encrypted_event_message(client); } nvnc_log(NVNC_LOG_WARNING, "Got uninterpretable message from client: %p",