vnc+spice: password-secret option.
bugfixes for cocoa, vnc, opengl. -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEoDKM/7k6F6eZAf59TLbY7tPocTgFAmBQRDYACgkQTLbY7tPo cTj2Qg//d3Pt0v9yiEvj5K+UxSl2ogKhNHLXDiN9eK0SrFcEQWaD0FqqbYLn3o8A oBG2rW6HlpBUiB07dNl9NKu53FvFqDGFgTMvrFzbLDsOrGpxJZe2kcf0rBqbuagT owEv4cqFaW6hHzWQTGkE55cBxgoVJLRcpyhINbt6Q1ryBNTPqKBkSrfhvCQtpVOC He0meGT52F8dHNJwEBe+wzOLPBmO+EtLslVyb5f12o+BmQLcvHcA9LCDdUYUAa7e yppreE8Z7Xwaix31MPMntnclRBrLab0X55DHhC6yUgm9430vRrN055xrcvEnlfit FTE9L9zOX049GdJWvYQKDUllABoB+wo1kXFkFQeSqiOTXkGP4uc3S3GO5BKwMNuC 0dBwEEAYJ5h2gaiY+csAmU6aj2nxb/2apbsoYEGLmRthbp5/XnJcxbAteEBuIoHr YsBemb/Zweb4+CvECFl9tWFIhhgSMQqMGPh4NsgsCk0I+dwRb7aoFo32ycxqdHCF jqpFOjF527aGFo6XGUY2/DdRSELMXHupqObWTAGBQQAfePMv6MMvrCY9+KYtpkO8 awgfGgLU1B70qGQ8v6kLANHE7ZyC36PC3P+unFSjB1CBRN2VJTII23lJkxjqjhkh bdwF4no460pCQs28M83f/jEnKuJvcLmYAj8Wi4goA/Wp6gboHxw= =Ma/x -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/kraxel/tags/ui-20210316-pull-request' into staging vnc+spice: password-secret option. bugfixes for cocoa, vnc, opengl. # gpg: Signature made Tue 16 Mar 2021 05:37:58 GMT # gpg: using RSA key A0328CFFB93A17A79901FE7D4CB6D8EED3E87138 # gpg: Good signature from "Gerd Hoffmann (work) <kraxel@redhat.com>" [full] # gpg: aka "Gerd Hoffmann <gerd@kraxel.org>" [full] # gpg: aka "Gerd Hoffmann (private) <kraxel@gmail.com>" [full] # Primary key fingerprint: A032 8CFF B93A 17A7 9901 FE7D 4CB6 D8EE D3E8 7138 * remotes/kraxel/tags/ui-20210316-pull-request: ui/cocoa: Comment about modifier key input quirks ui: fold qemu_alloc_display in only caller ui: honour the actual guest display dimensions without rounding ui: use client width/height in WMVi message ui: avoid sending framebuffer updates outside client desktop bounds ui: add more trace points for VNC client/server messages ui/cocoa: Do not exit immediately after shutdown opengl: Do not convert format with glTexImage2D on OpenGL ES ui: deprecate "password" option for SPICE server ui: introduce "password-secret" option for SPICE server ui: introduce "password-secret" option for VNC servers Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
25a7751043
@ -165,6 +165,14 @@ Input parameters that take a size value should only use a size suffix
|
||||
the value is hexadecimal. That is, '0x20M' is deprecated, and should
|
||||
be written either as '32M' or as '0x2000000'.
|
||||
|
||||
``-spice password=string`` (since 6.0)
|
||||
''''''''''''''''''''''''''''''''''''''
|
||||
|
||||
This option is insecure because the SPICE password remains visible in
|
||||
the process listing. This is replaced by the new ``password-secret``
|
||||
option which lets the password be securely provided on the command
|
||||
line using a ``secret`` object instance.
|
||||
|
||||
QEMU Machine Protocol (QMP) commands
|
||||
------------------------------------
|
||||
|
||||
|
@ -1922,7 +1922,8 @@ DEF("spice", HAS_ARG, QEMU_OPTION_spice,
|
||||
" [,tls-ciphers=<list>]\n"
|
||||
" [,tls-channel=[main|display|cursor|inputs|record|playback]]\n"
|
||||
" [,plaintext-channel=[main|display|cursor|inputs|record|playback]]\n"
|
||||
" [,sasl=on|off][,password=<secret>][,disable-ticketing=on|off]\n"
|
||||
" [,sasl=on|off][,disable-ticketing=on|off]\n"
|
||||
" [,password=<string>][,password-secret=<secret-id>]\n"
|
||||
" [,image-compression=[auto_glz|auto_lz|quic|glz|lz|off]]\n"
|
||||
" [,jpeg-wan-compression=[auto|never|always]]\n"
|
||||
" [,zlib-glz-wan-compression=[auto|never|always]]\n"
|
||||
@ -1947,9 +1948,17 @@ SRST
|
||||
``ipv4=on|off``; \ ``ipv6=on|off``; \ ``unix=on|off``
|
||||
Force using the specified IP version.
|
||||
|
||||
``password=<secret>``
|
||||
``password=<string>``
|
||||
Set the password you need to authenticate.
|
||||
|
||||
This option is deprecated and insecure because it leaves the
|
||||
password visible in the process listing. Use ``password-secret``
|
||||
instead.
|
||||
|
||||
``password-secret=<secret-id>``
|
||||
Set the ID of the ``secret`` object containing the password
|
||||
you need to authenticate.
|
||||
|
||||
``sasl=on|off``
|
||||
Require that the client use SASL to authenticate with the spice.
|
||||
The exact choice of authentication method used is controlled
|
||||
@ -2188,6 +2197,11 @@ SRST
|
||||
time to allow <protocol> password to expire immediately or never
|
||||
expire.
|
||||
|
||||
``password-secret=<secret-id>``
|
||||
Require that password based authentication is used for client
|
||||
connections, using the password provided by the ``secret``
|
||||
object identified by ``secret-id``.
|
||||
|
||||
``tls-creds=ID``
|
||||
Provides the ID of a set of TLS credentials to use to secure the
|
||||
VNC server. They will apply to both the normal VNC server socket
|
||||
|
46
ui/cocoa.m
46
ui/cocoa.m
@ -690,7 +690,43 @@ QemuCocoaView *cocoaView;
|
||||
NSPoint p = [self screenLocationOfEvent:event];
|
||||
NSUInteger modifiers = [event modifierFlags];
|
||||
|
||||
// emulate caps lock keydown and keyup
|
||||
/*
|
||||
* Check -[NSEvent modifierFlags] here.
|
||||
*
|
||||
* There is a NSEventType for an event notifying the change of
|
||||
* -[NSEvent modifierFlags], NSEventTypeFlagsChanged but these operations
|
||||
* are performed for any events because a modifier state may change while
|
||||
* the application is inactive (i.e. no events fire) and we don't want to
|
||||
* wait for another modifier state change to detect such a change.
|
||||
*
|
||||
* NSEventModifierFlagCapsLock requires a special treatment. The other flags
|
||||
* are handled in similar manners.
|
||||
*
|
||||
* NSEventModifierFlagCapsLock
|
||||
* ---------------------------
|
||||
*
|
||||
* If CapsLock state is changed, "up" and "down" events will be fired in
|
||||
* sequence, effectively updates CapsLock state on the guest.
|
||||
*
|
||||
* The other flags
|
||||
* ---------------
|
||||
*
|
||||
* If a flag is not set, fire "up" events for all keys which correspond to
|
||||
* the flag. Note that "down" events are not fired here because the flags
|
||||
* checked here do not tell what exact keys are down.
|
||||
*
|
||||
* If one of the keys corresponding to a flag is down, we rely on
|
||||
* -[NSEvent keyCode] of an event whose -[NSEvent type] is
|
||||
* NSEventTypeFlagsChanged to know the exact key which is down, which has
|
||||
* the following two downsides:
|
||||
* - It does not work when the application is inactive as described above.
|
||||
* - It malfactions *after* the modifier state is changed while the
|
||||
* application is inactive. It is because -[NSEvent keyCode] does not tell
|
||||
* if the key is up or down, and requires to infer the current state from
|
||||
* the previous state. It is still possible to fix such a malfanction by
|
||||
* completely leaving your hands from the keyboard, which hopefully makes
|
||||
* this implementation usable enough.
|
||||
*/
|
||||
if (!!(modifiers & NSEventModifierFlagCapsLock) !=
|
||||
qkbd_state_modifier_get(kbd, QKBD_MOD_CAPSLOCK)) {
|
||||
qkbd_state_key_event(kbd, Q_KEY_CODE_CAPS_LOCK, true);
|
||||
@ -1115,7 +1151,13 @@ QemuCocoaView *cocoaView;
|
||||
COCOA_DEBUG("QemuCocoaAppController: applicationWillTerminate\n");
|
||||
|
||||
qemu_system_shutdown_request(SHUTDOWN_CAUSE_HOST_UI);
|
||||
exit(0);
|
||||
|
||||
/*
|
||||
* Sleep here, because returning will cause OSX to kill us
|
||||
* immediately; the QEMU main loop will handle the shutdown
|
||||
* request and terminate the process.
|
||||
*/
|
||||
[NSThread sleepForTimeInterval:INFINITY];
|
||||
}
|
||||
|
||||
- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication
|
||||
|
@ -73,11 +73,20 @@ void surface_gl_create_texture(QemuGLShader *gls,
|
||||
glBindTexture(GL_TEXTURE_2D, surface->texture);
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT,
|
||||
surface_stride(surface) / surface_bytes_per_pixel(surface));
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB,
|
||||
surface_width(surface),
|
||||
surface_height(surface),
|
||||
0, surface->glformat, surface->gltype,
|
||||
surface_data(surface));
|
||||
if (epoxy_is_desktop_gl()) {
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB,
|
||||
surface_width(surface),
|
||||
surface_height(surface),
|
||||
0, surface->glformat, surface->gltype,
|
||||
surface_data(surface));
|
||||
} else {
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, surface->glformat,
|
||||
surface_width(surface),
|
||||
surface_height(surface),
|
||||
0, surface->glformat, surface->gltype,
|
||||
surface_data(surface));
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, GL_ONE);
|
||||
}
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
|
22
ui/console.c
22
ui/console.c
@ -1386,26 +1386,18 @@ static QemuConsole *new_console(DisplayState *ds, console_type_t console_type,
|
||||
return s;
|
||||
}
|
||||
|
||||
static void qemu_alloc_display(DisplaySurface *surface, int width, int height)
|
||||
{
|
||||
qemu_pixman_image_unref(surface->image);
|
||||
surface->image = NULL;
|
||||
|
||||
surface->format = PIXMAN_x8r8g8b8;
|
||||
surface->image = pixman_image_create_bits(surface->format,
|
||||
width, height,
|
||||
NULL, width * 4);
|
||||
assert(surface->image != NULL);
|
||||
|
||||
surface->flags = QEMU_ALLOCATED_FLAG;
|
||||
}
|
||||
|
||||
DisplaySurface *qemu_create_displaysurface(int width, int height)
|
||||
{
|
||||
DisplaySurface *surface = g_new0(DisplaySurface, 1);
|
||||
|
||||
trace_displaysurface_create(surface, width, height);
|
||||
qemu_alloc_display(surface, width, height);
|
||||
surface->format = PIXMAN_x8r8g8b8;
|
||||
surface->image = pixman_image_create_bits(surface->format,
|
||||
width, height,
|
||||
NULL, width * 4);
|
||||
assert(surface->image != NULL);
|
||||
surface->flags = QEMU_ALLOCATED_FLAG;
|
||||
|
||||
return surface;
|
||||
}
|
||||
|
||||
|
@ -34,6 +34,7 @@
|
||||
#include "qapi/qapi-events-ui.h"
|
||||
#include "qemu/notify.h"
|
||||
#include "qemu/option.h"
|
||||
#include "crypto/secret_common.h"
|
||||
#include "migration/misc.h"
|
||||
#include "hw/pci/pci_bus.h"
|
||||
#include "ui/spice-display.h"
|
||||
@ -415,6 +416,9 @@ static QemuOptsList qemu_spice_opts = {
|
||||
},{
|
||||
.name = "password",
|
||||
.type = QEMU_OPT_STRING,
|
||||
},{
|
||||
.name = "password-secret",
|
||||
.type = QEMU_OPT_STRING,
|
||||
},{
|
||||
.name = "disable-ticketing",
|
||||
.type = QEMU_OPT_BOOL,
|
||||
@ -636,7 +640,9 @@ void qemu_spice_display_init_done(void)
|
||||
static void qemu_spice_init(void)
|
||||
{
|
||||
QemuOpts *opts = QTAILQ_FIRST(&qemu_spice_opts.head);
|
||||
const char *password, *str, *x509_dir, *addr,
|
||||
char *password = NULL;
|
||||
const char *passwordSecret;
|
||||
const char *str, *x509_dir, *addr,
|
||||
*x509_key_password = NULL,
|
||||
*x509_dh_file = NULL,
|
||||
*tls_ciphers = NULL;
|
||||
@ -663,7 +669,28 @@ static void qemu_spice_init(void)
|
||||
error_report("spice tls-port is out of range");
|
||||
exit(1);
|
||||
}
|
||||
password = qemu_opt_get(opts, "password");
|
||||
passwordSecret = qemu_opt_get(opts, "password-secret");
|
||||
if (passwordSecret) {
|
||||
Error *local_err = NULL;
|
||||
if (qemu_opt_get(opts, "password")) {
|
||||
error_report("'password' option is mutually exclusive with "
|
||||
"'password-secret'");
|
||||
exit(1);
|
||||
}
|
||||
password = qcrypto_secret_lookup_as_utf8(passwordSecret,
|
||||
&local_err);
|
||||
if (!password) {
|
||||
error_report_err(local_err);
|
||||
exit(1);
|
||||
}
|
||||
} else {
|
||||
str = qemu_opt_get(opts, "password");
|
||||
if (str) {
|
||||
warn_report("'password' option is deprecated and insecure, "
|
||||
"use 'password-secret' instead");
|
||||
password = g_strdup(str);
|
||||
}
|
||||
}
|
||||
|
||||
if (tls_port) {
|
||||
x509_dir = qemu_opt_get(opts, "x509-dir");
|
||||
@ -809,6 +836,7 @@ static void qemu_spice_init(void)
|
||||
g_free(x509_key_file);
|
||||
g_free(x509_cert_file);
|
||||
g_free(x509_cacert_file);
|
||||
g_free(password);
|
||||
|
||||
#ifdef HAVE_SPICE_GL
|
||||
if (qemu_opt_get_bool(opts, "gl", 0)) {
|
||||
|
@ -37,6 +37,15 @@ vnc_key_event_ext(bool down, int sym, int keycode, const char *name) "down %d, s
|
||||
vnc_key_event_map(bool down, int sym, int keycode, const char *name) "down %d, sym 0x%x -> keycode 0x%x [%s]"
|
||||
vnc_key_sync_numlock(bool on) "%d"
|
||||
vnc_key_sync_capslock(bool on) "%d"
|
||||
vnc_msg_server_audio_begin(void *state, void *ioc) "VNC server msg audio begin state=%p ioc=%p"
|
||||
vnc_msg_server_audio_end(void *state, void *ioc) "VNC server msg audio end state=%p ioc=%p"
|
||||
vnc_msg_server_audio_data(void *state, void *ioc, const void *buf, size_t len) "VNC server msg audio data state=%p ioc=%p buf=%p len=%zd"
|
||||
vnc_msg_server_desktop_resize(void *state, void *ioc, int width, int height) "VNC server msg ext resize state=%p ioc=%p size=%dx%d"
|
||||
vnc_msg_server_ext_desktop_resize(void *state, void *ioc, int width, int height, int reason) "VNC server msg ext resize state=%p ioc=%p size=%dx%d reason=%d"
|
||||
vnc_msg_client_audio_enable(void *state, void *ioc) "VNC client msg audio enable state=%p ioc=%p"
|
||||
vnc_msg_client_audio_disable(void *state, void *ioc) "VNC client msg audio disable state=%p ioc=%p"
|
||||
vnc_msg_client_audio_format(void *state, void *ioc, int fmt, int channels, int freq) "VNC client msg audio format state=%p ioc=%p fmt=%d channels=%d freq=%d"
|
||||
vnc_msg_client_set_desktop_size(void *state, void *ioc, int width, int height, int screens) "VNC client msg set desktop size state=%p ioc=%p size=%dx%d screens=%d"
|
||||
vnc_client_eof(void *state, void *ioc) "VNC client EOF state=%p ioc=%p"
|
||||
vnc_client_io_error(void *state, void *ioc, const char *msg) "VNC client I/O error state=%p ioc=%p errmsg=%s"
|
||||
vnc_client_connect(void *state, void *ioc) "VNC client connect state=%p ioc=%p"
|
||||
@ -50,6 +59,13 @@ vnc_client_throttle_audio(void *state, void *ioc, size_t offset) "VNC client thr
|
||||
vnc_client_unthrottle_forced(void *state, void *ioc) "VNC client unthrottle forced offset state=%p ioc=%p"
|
||||
vnc_client_unthrottle_incremental(void *state, void *ioc, size_t offset) "VNC client unthrottle incremental state=%p ioc=%p offset=%zu"
|
||||
vnc_client_output_limit(void *state, void *ioc, size_t offset, size_t threshold) "VNC client output limit state=%p ioc=%p offset=%zu threshold=%zu"
|
||||
vnc_server_dpy_pageflip(void *dpy, int w, int h, int fmt) "VNC server dpy pageflip dpy=%p size=%dx%d fmt=%d"
|
||||
vnc_server_dpy_recreate(void *dpy, int w, int h, int fmt) "VNC server dpy recreate dpy=%p size=%dx%d fmt=%d"
|
||||
vnc_job_add_rect(void *state, void *job, int x, int y, int w, int h) "VNC add rect state=%p job=%p offset=%d,%d size=%dx%d"
|
||||
vnc_job_discard_rect(void *state, void *job, int x, int y, int w, int h) "VNC job discard rect state=%p job=%p offset=%d,%d size=%dx%d"
|
||||
vnc_job_clamp_rect(void *state, void *job, int x, int y, int w, int h) "VNC job clamp rect state=%p job=%p offset=%d,%d size=%dx%d"
|
||||
vnc_job_clamped_rect(void *state, void *job, int x, int y, int w, int h) "VNC job clamp rect state=%p job=%p offset=%d,%d size=%dx%d"
|
||||
vnc_job_nrects(void *state, void *job, int nrects) "VNC job state=%p job=%p nrects=%d"
|
||||
vnc_auth_init(void *display, int websock, int auth, int subauth) "VNC auth init state=%p websock=%d auth=%d subauth=%d"
|
||||
vnc_auth_start(void *state, int method) "VNC client auth start state=%p method=%d"
|
||||
vnc_auth_pass(void *state, int method) "VNC client auth passed state=%p method=%d"
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include "qemu/sockets.h"
|
||||
#include "qemu/main-loop.h"
|
||||
#include "block/aio.h"
|
||||
#include "trace.h"
|
||||
|
||||
/*
|
||||
* Locking:
|
||||
@ -94,6 +95,8 @@ int vnc_job_add_rect(VncJob *job, int x, int y, int w, int h)
|
||||
{
|
||||
VncRectEntry *entry = g_new0(VncRectEntry, 1);
|
||||
|
||||
trace_vnc_job_add_rect(job->vs, job, x, y, w, h);
|
||||
|
||||
entry->rect.x = x;
|
||||
entry->rect.y = y;
|
||||
entry->rect.w = w;
|
||||
@ -190,6 +193,8 @@ static void vnc_async_encoding_start(VncState *orig, VncState *local)
|
||||
local->zlib = orig->zlib;
|
||||
local->hextile = orig->hextile;
|
||||
local->zrle = orig->zrle;
|
||||
local->client_width = orig->client_width;
|
||||
local->client_height = orig->client_height;
|
||||
}
|
||||
|
||||
static void vnc_async_encoding_end(VncState *orig, VncState *local)
|
||||
@ -202,6 +207,34 @@ static void vnc_async_encoding_end(VncState *orig, VncState *local)
|
||||
orig->lossy_rect = local->lossy_rect;
|
||||
}
|
||||
|
||||
static bool vnc_worker_clamp_rect(VncState *vs, VncJob *job, VncRect *rect)
|
||||
{
|
||||
trace_vnc_job_clamp_rect(vs, job, rect->x, rect->y, rect->w, rect->h);
|
||||
|
||||
if (rect->x >= vs->client_width) {
|
||||
goto discard;
|
||||
}
|
||||
rect->w = MIN(vs->client_width - rect->x, rect->w);
|
||||
if (rect->w == 0) {
|
||||
goto discard;
|
||||
}
|
||||
|
||||
if (rect->y >= vs->client_height) {
|
||||
goto discard;
|
||||
}
|
||||
rect->h = MIN(vs->client_height - rect->y, rect->h);
|
||||
if (rect->h == 0) {
|
||||
goto discard;
|
||||
}
|
||||
|
||||
trace_vnc_job_clamped_rect(vs, job, rect->x, rect->y, rect->w, rect->h);
|
||||
return true;
|
||||
|
||||
discard:
|
||||
trace_vnc_job_discard_rect(vs, job, rect->x, rect->y, rect->w, rect->h);
|
||||
return false;
|
||||
}
|
||||
|
||||
static int vnc_worker_thread_loop(VncJobQueue *queue)
|
||||
{
|
||||
VncJob *job;
|
||||
@ -260,14 +293,17 @@ static int vnc_worker_thread_loop(VncJobQueue *queue)
|
||||
goto disconnected;
|
||||
}
|
||||
|
||||
n = vnc_send_framebuffer_update(&vs, entry->rect.x, entry->rect.y,
|
||||
entry->rect.w, entry->rect.h);
|
||||
if (vnc_worker_clamp_rect(&vs, job, &entry->rect)) {
|
||||
n = vnc_send_framebuffer_update(&vs, entry->rect.x, entry->rect.y,
|
||||
entry->rect.w, entry->rect.h);
|
||||
|
||||
if (n >= 0) {
|
||||
n_rectangles += n;
|
||||
if (n >= 0) {
|
||||
n_rectangles += n;
|
||||
}
|
||||
}
|
||||
g_free(entry);
|
||||
}
|
||||
trace_vnc_job_nrects(&vs, job, n_rectangles);
|
||||
vnc_unlock_display(job->vs->vd);
|
||||
|
||||
/* Put n_rectangles at the beginning of the message */
|
||||
|
71
ui/vnc.c
71
ui/vnc.c
@ -48,6 +48,7 @@
|
||||
#include "crypto/tlscredsanon.h"
|
||||
#include "crypto/tlscredsx509.h"
|
||||
#include "crypto/random.h"
|
||||
#include "crypto/secret_common.h"
|
||||
#include "qom/object_interfaces.h"
|
||||
#include "qemu/cutils.h"
|
||||
#include "qemu/help_option.h"
|
||||
@ -607,6 +608,11 @@ static int vnc_width(VncDisplay *vd)
|
||||
VNC_DIRTY_PIXELS_PER_BIT));
|
||||
}
|
||||
|
||||
static int vnc_true_width(VncDisplay *vd)
|
||||
{
|
||||
return MIN(VNC_MAX_WIDTH, surface_width(vd->ds));
|
||||
}
|
||||
|
||||
static int vnc_height(VncDisplay *vd)
|
||||
{
|
||||
return MIN(VNC_MAX_HEIGHT, surface_height(vd->ds));
|
||||
@ -658,6 +664,9 @@ void vnc_framebuffer_update(VncState *vs, int x, int y, int w, int h,
|
||||
|
||||
static void vnc_desktop_resize_ext(VncState *vs, int reject_reason)
|
||||
{
|
||||
trace_vnc_msg_server_ext_desktop_resize(
|
||||
vs, vs->ioc, vs->client_width, vs->client_height, reject_reason);
|
||||
|
||||
vnc_lock_output(vs);
|
||||
vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
|
||||
vnc_write_u8(vs, 0);
|
||||
@ -687,16 +696,16 @@ static void vnc_desktop_resize(VncState *vs)
|
||||
!vnc_has_feature(vs, VNC_FEATURE_RESIZE_EXT))) {
|
||||
return;
|
||||
}
|
||||
if (vs->client_width == pixman_image_get_width(vs->vd->server) &&
|
||||
if (vs->client_width == vs->vd->true_width &&
|
||||
vs->client_height == pixman_image_get_height(vs->vd->server)) {
|
||||
return;
|
||||
}
|
||||
|
||||
assert(pixman_image_get_width(vs->vd->server) < 65536 &&
|
||||
pixman_image_get_width(vs->vd->server) >= 0);
|
||||
assert(vs->vd->true_width < 65536 &&
|
||||
vs->vd->true_width >= 0);
|
||||
assert(pixman_image_get_height(vs->vd->server) < 65536 &&
|
||||
pixman_image_get_height(vs->vd->server) >= 0);
|
||||
vs->client_width = pixman_image_get_width(vs->vd->server);
|
||||
vs->client_width = vs->vd->true_width;
|
||||
vs->client_height = pixman_image_get_height(vs->vd->server);
|
||||
|
||||
if (vnc_has_feature(vs, VNC_FEATURE_RESIZE_EXT)) {
|
||||
@ -704,6 +713,9 @@ static void vnc_desktop_resize(VncState *vs)
|
||||
return;
|
||||
}
|
||||
|
||||
trace_vnc_msg_server_desktop_resize(
|
||||
vs, vs->ioc, vs->client_width, vs->client_height);
|
||||
|
||||
vnc_lock_output(vs);
|
||||
vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
|
||||
vnc_write_u8(vs, 0);
|
||||
@ -767,6 +779,7 @@ static void vnc_update_server_surface(VncDisplay *vd)
|
||||
|
||||
width = vnc_width(vd);
|
||||
height = vnc_height(vd);
|
||||
vd->true_width = vnc_true_width(vd);
|
||||
vd->server = pixman_image_create_bits(VNC_SERVER_FB_FORMAT,
|
||||
width, height,
|
||||
NULL, 0);
|
||||
@ -802,13 +815,22 @@ static void vnc_dpy_switch(DisplayChangeListener *dcl,
|
||||
vd->guest.fb = pixman_image_ref(surface->image);
|
||||
vd->guest.format = surface->format;
|
||||
|
||||
|
||||
if (pageflip) {
|
||||
trace_vnc_server_dpy_pageflip(vd,
|
||||
surface_width(surface),
|
||||
surface_height(surface),
|
||||
surface_format(surface));
|
||||
vnc_set_area_dirty(vd->guest.dirty, vd, 0, 0,
|
||||
surface_width(surface),
|
||||
surface_height(surface));
|
||||
return;
|
||||
}
|
||||
|
||||
trace_vnc_server_dpy_recreate(vd,
|
||||
surface_width(surface),
|
||||
surface_height(surface),
|
||||
surface_format(surface));
|
||||
/* server surface */
|
||||
vnc_update_server_surface(vd);
|
||||
|
||||
@ -1181,6 +1203,7 @@ static void audio_capture_notify(void *opaque, audcnotification_e cmd)
|
||||
assert(vs->magic == VNC_MAGIC);
|
||||
switch (cmd) {
|
||||
case AUD_CNOTIFY_DISABLE:
|
||||
trace_vnc_msg_server_audio_end(vs, vs->ioc);
|
||||
vnc_lock_output(vs);
|
||||
vnc_write_u8(vs, VNC_MSG_SERVER_QEMU);
|
||||
vnc_write_u8(vs, VNC_MSG_SERVER_QEMU_AUDIO);
|
||||
@ -1190,6 +1213,7 @@ static void audio_capture_notify(void *opaque, audcnotification_e cmd)
|
||||
break;
|
||||
|
||||
case AUD_CNOTIFY_ENABLE:
|
||||
trace_vnc_msg_server_audio_begin(vs, vs->ioc);
|
||||
vnc_lock_output(vs);
|
||||
vnc_write_u8(vs, VNC_MSG_SERVER_QEMU);
|
||||
vnc_write_u8(vs, VNC_MSG_SERVER_QEMU_AUDIO);
|
||||
@ -1209,6 +1233,7 @@ static void audio_capture(void *opaque, const void *buf, int size)
|
||||
VncState *vs = opaque;
|
||||
|
||||
assert(vs->magic == VNC_MAGIC);
|
||||
trace_vnc_msg_server_audio_data(vs, vs->ioc, buf, size);
|
||||
vnc_lock_output(vs);
|
||||
if (vs->output.offset < vs->throttle_output_offset) {
|
||||
vnc_write_u8(vs, VNC_MSG_SERVER_QEMU);
|
||||
@ -2309,8 +2334,8 @@ static void vnc_colordepth(VncState *vs)
|
||||
vnc_write_u8(vs, 0);
|
||||
vnc_write_u16(vs, 1); /* number of rects */
|
||||
vnc_framebuffer_update(vs, 0, 0,
|
||||
pixman_image_get_width(vs->vd->server),
|
||||
pixman_image_get_height(vs->vd->server),
|
||||
vs->client_width,
|
||||
vs->client_height,
|
||||
VNC_ENCODING_WMVi);
|
||||
pixel_format_message(vs);
|
||||
vnc_unlock_output(vs);
|
||||
@ -2453,9 +2478,11 @@ static int protocol_client_msg(VncState *vs, uint8_t *data, size_t len)
|
||||
|
||||
switch (read_u16 (data, 2)) {
|
||||
case VNC_MSG_CLIENT_QEMU_AUDIO_ENABLE:
|
||||
trace_vnc_msg_client_audio_enable(vs, vs->ioc);
|
||||
audio_add(vs);
|
||||
break;
|
||||
case VNC_MSG_CLIENT_QEMU_AUDIO_DISABLE:
|
||||
trace_vnc_msg_client_audio_disable(vs, vs->ioc);
|
||||
audio_del(vs);
|
||||
break;
|
||||
case VNC_MSG_CLIENT_QEMU_AUDIO_SET_FORMAT:
|
||||
@ -2491,6 +2518,8 @@ static int protocol_client_msg(VncState *vs, uint8_t *data, size_t len)
|
||||
break;
|
||||
}
|
||||
vs->as.freq = freq;
|
||||
trace_vnc_msg_client_audio_format(
|
||||
vs, vs->ioc, vs->as.fmt, vs->as.nchannels, vs->as.freq);
|
||||
break;
|
||||
default:
|
||||
VNC_DEBUG("Invalid audio message %d\n", read_u8(data, 4));
|
||||
@ -2509,6 +2538,7 @@ static int protocol_client_msg(VncState *vs, uint8_t *data, size_t len)
|
||||
{
|
||||
size_t size;
|
||||
uint8_t screens;
|
||||
int w, h;
|
||||
|
||||
if (len < 8) {
|
||||
return 8;
|
||||
@ -2519,12 +2549,15 @@ static int protocol_client_msg(VncState *vs, uint8_t *data, size_t len)
|
||||
if (len < size) {
|
||||
return size;
|
||||
}
|
||||
w = read_u16(data, 2);
|
||||
h = read_u16(data, 4);
|
||||
|
||||
trace_vnc_msg_client_set_desktop_size(vs, vs->ioc, w, h, screens);
|
||||
if (dpy_ui_info_supported(vs->vd->dcl.con)) {
|
||||
QemuUIInfo info;
|
||||
memset(&info, 0, sizeof(info));
|
||||
info.width = read_u16(data, 2);
|
||||
info.height = read_u16(data, 4);
|
||||
info.width = w;
|
||||
info.height = h;
|
||||
dpy_set_ui_info(vs->vd->dcl.con, &info);
|
||||
vnc_desktop_resize_ext(vs, 4 /* Request forwarded */);
|
||||
} else {
|
||||
@ -3459,6 +3492,9 @@ static QemuOptsList qemu_vnc_opts = {
|
||||
},{
|
||||
.name = "password",
|
||||
.type = QEMU_OPT_BOOL,
|
||||
},{
|
||||
.name = "password-secret",
|
||||
.type = QEMU_OPT_STRING,
|
||||
},{
|
||||
.name = "reverse",
|
||||
.type = QEMU_OPT_BOOL,
|
||||
@ -3931,6 +3967,7 @@ void vnc_display_open(const char *id, Error **errp)
|
||||
int lock_key_sync = 1;
|
||||
int key_delay_ms;
|
||||
const char *audiodev;
|
||||
const char *passwordSecret;
|
||||
|
||||
if (!vd) {
|
||||
error_setg(errp, "VNC display not active");
|
||||
@ -3948,7 +3985,23 @@ void vnc_display_open(const char *id, Error **errp)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
password = qemu_opt_get_bool(opts, "password", false);
|
||||
|
||||
passwordSecret = qemu_opt_get(opts, "password-secret");
|
||||
if (passwordSecret) {
|
||||
if (qemu_opt_get(opts, "password")) {
|
||||
error_setg(errp,
|
||||
"'password' flag is redundant with 'password-secret'");
|
||||
goto fail;
|
||||
}
|
||||
vd->password = qcrypto_secret_lookup_as_utf8(passwordSecret,
|
||||
errp);
|
||||
if (!vd->password) {
|
||||
goto fail;
|
||||
}
|
||||
password = true;
|
||||
} else {
|
||||
password = qemu_opt_get_bool(opts, "password", false);
|
||||
}
|
||||
if (password) {
|
||||
if (fips_get_state()) {
|
||||
error_setg(errp,
|
||||
|
Loading…
Reference in New Issue
Block a user