?? vnc.c
字號:
} if (bits_per_pixel == 32 && host_big_endian_flag == big_endian_flag && red_max == 0xff && green_max == 0xff && blue_max == 0xff && red_shift == 16 && green_shift == 8 && blue_shift == 0) { vs->depth = 4; vs->write_pixels = vnc_write_pixels_copy; vs->send_hextile_tile = send_hextile_tile_32; } else if (bits_per_pixel == 16 && host_big_endian_flag == big_endian_flag && red_max == 31 && green_max == 63 && blue_max == 31 && red_shift == 11 && green_shift == 5 && blue_shift == 0) { vs->depth = 2; vs->write_pixels = vnc_write_pixels_copy; vs->send_hextile_tile = send_hextile_tile_16; } else if (bits_per_pixel == 8 && red_max == 7 && green_max == 7 && blue_max == 3 && red_shift == 5 && green_shift == 2 && blue_shift == 0) { vs->depth = 1; vs->write_pixels = vnc_write_pixels_copy; vs->send_hextile_tile = send_hextile_tile_8; } else { /* generic and slower case */ if (bits_per_pixel != 8 && bits_per_pixel != 16 && bits_per_pixel != 32) goto fail; vs->depth = 4; vs->red_shift = red_shift; vs->red_max = red_max; vs->red_shift1 = 24 - compute_nbits(red_max); vs->green_shift = green_shift; vs->green_max = green_max; vs->green_shift1 = 16 - compute_nbits(green_max); vs->blue_shift = blue_shift; vs->blue_max = blue_max; vs->blue_shift1 = 8 - compute_nbits(blue_max); vs->pix_bpp = bits_per_pixel / 8; vs->pix_big_endian = big_endian_flag; vs->write_pixels = vnc_write_pixels_generic; vs->send_hextile_tile = send_hextile_tile_generic; } vnc_dpy_resize(vs->ds, vs->ds->width, vs->ds->height); memset(vs->dirty_row, 0xFF, sizeof(vs->dirty_row)); memset(vs->old_data, 42, vs->ds->linesize * vs->ds->height); vga_hw_invalidate(); vga_hw_update();}static int protocol_client_msg(VncState *vs, uint8_t *data, size_t len){ int i; uint16_t limit; switch (data[0]) { case 0: if (len == 1) return 20; set_pixel_format(vs, read_u8(data, 4), read_u8(data, 5), read_u8(data, 6), read_u8(data, 7), read_u16(data, 8), read_u16(data, 10), read_u16(data, 12), read_u8(data, 14), read_u8(data, 15), read_u8(data, 16)); break; case 2: if (len == 1) return 4; if (len == 4) return 4 + (read_u16(data, 2) * 4); limit = read_u16(data, 2); for (i = 0; i < limit; i++) { int32_t val = read_s32(data, 4 + (i * 4)); memcpy(data + 4 + (i * 4), &val, sizeof(val)); } set_encodings(vs, (int32_t *)(data + 4), limit); break; case 3: if (len == 1) return 10; framebuffer_update_request(vs, read_u8(data, 1), read_u16(data, 2), read_u16(data, 4), read_u16(data, 6), read_u16(data, 8)); break; case 4: if (len == 1) return 8; key_event(vs, read_u8(data, 1), read_u32(data, 4)); break; case 5: if (len == 1) return 6; pointer_event(vs, read_u8(data, 1), read_u16(data, 2), read_u16(data, 4)); break; case 6: if (len == 1) return 8; if (len == 8) { uint32_t dlen = read_u32(data, 4); if (dlen > 0) return 8 + dlen; } client_cut_text(vs, read_u32(data, 4), data + 8); break; default: printf("Msg: %d\n", data[0]); vnc_client_error(vs); break; } vnc_read_when(vs, protocol_client_msg, 1); return 0;}static int protocol_client_init(VncState *vs, uint8_t *data, size_t len){ char pad[3] = { 0, 0, 0 }; char buf[1024]; int size; vs->width = vs->ds->width; vs->height = vs->ds->height; vnc_write_u16(vs, vs->ds->width); vnc_write_u16(vs, vs->ds->height); vnc_write_u8(vs, vs->depth * 8); /* bits-per-pixel */ vnc_write_u8(vs, vs->depth * 8); /* depth */#ifdef WORDS_BIGENDIAN vnc_write_u8(vs, 1); /* big-endian-flag */#else vnc_write_u8(vs, 0); /* big-endian-flag */#endif vnc_write_u8(vs, 1); /* true-color-flag */ if (vs->depth == 4) { vnc_write_u16(vs, 0xFF); /* red-max */ vnc_write_u16(vs, 0xFF); /* green-max */ vnc_write_u16(vs, 0xFF); /* blue-max */ vnc_write_u8(vs, 16); /* red-shift */ vnc_write_u8(vs, 8); /* green-shift */ vnc_write_u8(vs, 0); /* blue-shift */ vs->send_hextile_tile = send_hextile_tile_32; } else if (vs->depth == 2) { vnc_write_u16(vs, 31); /* red-max */ vnc_write_u16(vs, 63); /* green-max */ vnc_write_u16(vs, 31); /* blue-max */ vnc_write_u8(vs, 11); /* red-shift */ vnc_write_u8(vs, 5); /* green-shift */ vnc_write_u8(vs, 0); /* blue-shift */ vs->send_hextile_tile = send_hextile_tile_16; } else if (vs->depth == 1) { /* XXX: change QEMU pixel 8 bit pixel format to match the VNC one ? */ vnc_write_u16(vs, 7); /* red-max */ vnc_write_u16(vs, 7); /* green-max */ vnc_write_u16(vs, 3); /* blue-max */ vnc_write_u8(vs, 5); /* red-shift */ vnc_write_u8(vs, 2); /* green-shift */ vnc_write_u8(vs, 0); /* blue-shift */ vs->send_hextile_tile = send_hextile_tile_8; } vs->write_pixels = vnc_write_pixels_copy; vnc_write(vs, pad, 3); /* padding */ if (qemu_name) size = snprintf(buf, sizeof(buf), "QEMU (%s)", qemu_name); else size = snprintf(buf, sizeof(buf), "QEMU"); vnc_write_u32(vs, size); vnc_write(vs, buf, size); vnc_flush(vs); vnc_read_when(vs, protocol_client_msg, 1); return 0;}static void make_challenge(VncState *vs){ int i; srand(time(NULL)+getpid()+getpid()*987654+rand()); for (i = 0 ; i < sizeof(vs->challenge) ; i++) vs->challenge[i] = (int) (256.0*rand()/(RAND_MAX+1.0));}static int protocol_client_auth_vnc(VncState *vs, uint8_t *data, size_t len){ unsigned char response[VNC_AUTH_CHALLENGE_SIZE]; int i, j, pwlen; unsigned char key[8]; if (!vs->password || !vs->password[0]) { VNC_DEBUG("No password configured on server"); vnc_write_u32(vs, 1); /* Reject auth */ if (vs->minor >= 8) { static const char err[] = "Authentication failed"; vnc_write_u32(vs, sizeof(err)); vnc_write(vs, err, sizeof(err)); } vnc_flush(vs); vnc_client_error(vs); return 0; } memcpy(response, vs->challenge, VNC_AUTH_CHALLENGE_SIZE); /* Calculate the expected challenge response */ pwlen = strlen(vs->password); for (i=0; i<sizeof(key); i++) key[i] = i<pwlen ? vs->password[i] : 0; deskey(key, EN0); for (j = 0; j < VNC_AUTH_CHALLENGE_SIZE; j += 8) des(response+j, response+j); /* Compare expected vs actual challenge response */ if (memcmp(response, data, VNC_AUTH_CHALLENGE_SIZE) != 0) { VNC_DEBUG("Client challenge reponse did not match\n"); vnc_write_u32(vs, 1); /* Reject auth */ if (vs->minor >= 8) { static const char err[] = "Authentication failed"; vnc_write_u32(vs, sizeof(err)); vnc_write(vs, err, sizeof(err)); } vnc_flush(vs); vnc_client_error(vs); } else { VNC_DEBUG("Accepting VNC challenge response\n"); vnc_write_u32(vs, 0); /* Accept auth */ vnc_flush(vs); vnc_read_when(vs, protocol_client_init, 1); } return 0;}static int start_auth_vnc(VncState *vs){ make_challenge(vs); /* Send client a 'random' challenge */ vnc_write(vs, vs->challenge, sizeof(vs->challenge)); vnc_flush(vs); vnc_read_when(vs, protocol_client_auth_vnc, sizeof(vs->challenge)); return 0;}#if CONFIG_VNC_TLS#define DH_BITS 1024static gnutls_dh_params_t dh_params;static int vnc_tls_initialize(void){ static int tlsinitialized = 0; if (tlsinitialized) return 1; if (gnutls_global_init () < 0) return 0; /* XXX ought to re-generate diffie-hellmen params periodically */ if (gnutls_dh_params_init (&dh_params) < 0) return 0; if (gnutls_dh_params_generate2 (dh_params, DH_BITS) < 0) return 0;#if _VNC_DEBUG == 2 gnutls_global_set_log_level(10); gnutls_global_set_log_function(vnc_debug_gnutls_log);#endif tlsinitialized = 1; return 1;}static gnutls_anon_server_credentials vnc_tls_initialize_anon_cred(void){ gnutls_anon_server_credentials anon_cred; int ret; if ((ret = gnutls_anon_allocate_server_credentials(&anon_cred)) < 0) { VNC_DEBUG("Cannot allocate credentials %s\n", gnutls_strerror(ret)); return NULL; } gnutls_anon_set_server_dh_params(anon_cred, dh_params); return anon_cred;}static gnutls_certificate_credentials_t vnc_tls_initialize_x509_cred(VncState *vs){ gnutls_certificate_credentials_t x509_cred; int ret; if (!vs->x509cacert) { VNC_DEBUG("No CA x509 certificate specified\n"); return NULL; } if (!vs->x509cert) { VNC_DEBUG("No server x509 certificate specified\n"); return NULL; } if (!vs->x509key) { VNC_DEBUG("No server private key specified\n"); return NULL; } if ((ret = gnutls_certificate_allocate_credentials(&x509_cred)) < 0) { VNC_DEBUG("Cannot allocate credentials %s\n", gnutls_strerror(ret)); return NULL; } if ((ret = gnutls_certificate_set_x509_trust_file(x509_cred, vs->x509cacert, GNUTLS_X509_FMT_PEM)) < 0) { VNC_DEBUG("Cannot load CA certificate %s\n", gnutls_strerror(ret)); gnutls_certificate_free_credentials(x509_cred); return NULL; } if ((ret = gnutls_certificate_set_x509_key_file (x509_cred, vs->x509cert, vs->x509key, GNUTLS_X509_FMT_PEM)) < 0) { VNC_DEBUG("Cannot load certificate & key %s\n", gnutls_strerror(ret)); gnutls_certificate_free_credentials(x509_cred); return NULL; } if (vs->x509cacrl) { if ((ret = gnutls_certificate_set_x509_crl_file(x509_cred, vs->x509cacrl, GNUTLS_X509_FMT_PEM)) < 0) { VNC_DEBUG("Cannot load CRL %s\n", gnutls_strerror(ret)); gnutls_certificate_free_credentials(x509_cred); return NULL; } } gnutls_certificate_set_dh_params (x509_cred, dh_params); return x509_cred;}static int vnc_validate_certificate(struct VncState *vs){ int ret; unsigned int status; const gnutls_datum_t *certs; unsigned int nCerts, i; time_t now; VNC_DEBUG("Validating client certificate\n"); if ((ret = gnutls_certificate_verify_peers2 (vs->tls_session, &status)) < 0) { VNC_DEBUG("Verify failed %s\n", gnutls_strerror(ret)); return -1; } if ((now = time(NULL)) == ((time_t)-1)) { return -1; } if (status != 0) { if (status & GNUTLS_CERT_INVALID) VNC_DEBUG("The certificate is not trusted.\n"); if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) VNC_DEBUG("The certificate hasn't got a known issuer.\n"); if (status & GNUTLS_CERT_REVOKED) VNC_DEBUG("The certificate has been revoked.\n"); if (status & GNUTLS_CERT_INSECURE_ALGORITHM) VNC_DEBUG("The certificate uses an insecure algorithm\n"); return -1; } else { VNC_DEBUG("Certificate is valid!\n"); } /* Only support x509 for now */ if (gnutls_certificate_type_get(vs->tls_session) != GNUTLS_CRT_X509) return -1; if (!(certs = gnutls_certificate_get_peers(vs->tls_session, &nCerts))) return -1; for (i = 0 ; i < nCerts ; i++) { gnutls_x509_crt_t cert; VNC_DEBUG ("Checking certificate chain %d\n", i); if (gnutls_x509_crt_init (&cert) < 0) return -1; if (gnutls_x509_crt_import(cert, &certs[i], GNUTLS_X509_FMT_DER) < 0) { gnutls_x509_crt_deinit (cert); return -1; } if (gnutls_x509_crt_get_expiration_time (cert) < now) { VNC_DEBUG("The certificate has expired\n"); gnutls_x509_crt_deinit (cert); return -1; } if (gnutls_x509_crt_get_activation_time (cert) > now) { VNC_DEBUG("The certificate is not yet activated\n"); gnutls_x509_crt_deinit (cert); return -1; } if (gnutls_x509_crt_get_activation_time (cert) > now) { VNC_DEBUG("The certificate is not yet activated\n"); gnutls_x509_crt_deinit (cert); return -1; } gnutls_x509_crt_deinit (cert); } return 0;}static int start_auth_vencrypt_subauth(VncState *vs){ switch (vs->subauth) { case VNC_AUTH_VENCRYPT_TLSNONE: case VNC_AUTH_VENCRYPT_X509NONE: VNC_DEBUG("Accept TLS auth none\n"); vnc_write_u32(vs, 0); /* Accept auth completion */ vnc_read_when(vs, protocol_client_init, 1); break; case VNC_AUTH_VENCRYPT_TLSVNC: case VNC_AUTH_VENCRYPT_X509VNC: VNC_DEBUG("Start TLS auth VNC\n"); return start_auth_vnc(vs); default: /* Should not be possible, but just in case */ VNC_DEBUG("Reject auth %d\n", vs->auth); vnc_write_u8(vs, 1); if (vs->minor >= 8) { static const char err[] = "Unsupported authentication type"; vnc_write_u32(vs, sizeof(err)); vnc_write(vs, err, sizeof(err)); } vnc_client_error(vs); } return 0;}static void vnc_handshake_io(void *opaque);static int vnc_continue_handshake(struct VncState *vs) { int ret; if ((ret = gnutls_handshake(vs->tls_session)) < 0) { if (!gnutls_error_is_fatal(ret)) { VNC_DEBUG("Handshake interrupted (blocking)\n"); if (!gnutls_record_get_direction(vs->tls_session)) qemu_set_fd_handler(vs->csock, vnc_handshake_io, NULL, vs); else qemu_set_fd_handler(vs->csock, NULL, vnc_handshake_io, vs); return 0; } VNC_DEBUG("Handshake failed %s\n", gnutls_strerror(ret)); vnc_client_error(vs); return -1; } if (vs->x509verify) { if (vnc_validate_certificate(vs) < 0) { VNC_DEBUG("Client verification failed\n"); vnc_client_error(vs); return -1; } else { VNC_DEBUG("Client verification passed\n"); } } VNC_DEBUG("Handshake done, switching to TLS data mode\n"); vs->wiremode = VNC_WIREMODE_TLS; qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, vnc_client_write, vs); return start_auth_vencrypt_subauth(vs);}static void vnc_handshake_io(void *opaque) { struct VncState *vs = (struct VncState *)opaque; VNC_DEBUG("Handshake IO continue\n"); vnc_continue_handshake(vs);}#define NEED_X509_AUTH(vs) \ ((vs)->subauth == VNC_AUTH_VENCRYPT_X509NONE || \ (vs)->subauth == VNC_AUTH_VENCRYPT_X509VNC || \ (vs)->subauth == VNC_AUTH_VENCRYPT_X509PLAIN)static int vnc_start_tls(struct VncState *vs) { static const int cert_type_priority[] = { GNUTLS_CRT_X509, 0 }; static const int protocol_priority[]= { GNUTLS_TLS1_1, GNUTLS_TLS1_0, GNUTLS_SSL3, 0 }; static const int kx_anon[] = {GNUTLS_KX_ANON_DH, 0}; static const int kx_x509[] = {GNUTLS_KX_DHE_DSS, GNUTLS_KX_RSA, GNUTLS_KX_DHE_RSA, GNUTLS_KX_SRP, 0}; VNC_DEBUG("Do TLS setup\n"); if (vnc_tls_initialize() < 0) { VNC_DEBUG("Failed to init TLS\n"); vnc_client_error(vs); return -1; } if (vs->tls_session == NULL) { if (gnutls_init(&vs->tls_session, GNUTLS_SERVER) < 0) { vnc_client_error(vs); return -1; } if (gnutls_set_default_priority(vs->tls_session) < 0) { gnutls_deinit(vs->tls_session); vs->tls_session = NULL; vnc_client_error(vs); return -1; } if (gnutls_kx_set_priority(vs->tls_session, NEED_X509_AUTH(vs) ? kx_x509 : kx_anon) < 0) { gnutls_deinit(vs->tls_session); vs->tls_session = NULL; vnc_client_error(vs); return -1; } if (gnutls_certificate_type_set_priority(vs->tls_session, cert_type_priority) < 0) { gnutls_deinit(vs->tls_session); vs->tls_session = NULL; vnc_client_error(vs); return -1; } if (gnutls_protocol_set_priority(vs->tls_session, protocol_priority) < 0) { gnutls_deinit(vs->tls_session); vs->tls_session = NULL; vnc_client_error(vs); return -1; }
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -