mirror of
https://github.com/qemu/qemu.git
synced 2024-11-26 12:23:36 +08:00
ui: vnc cleanups, input-linux kbd fix.
-----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.22 (GNU/Linux) iQIcBAABAgAGBQJX/0ovAAoJEEy22O7T6HE4iA0P/1hkEtjA1kuF2cOc8TrLouPQ QZSWK3GK0ZqlHkzW22FPqhH7uAOyvcvqdKAzfgWoIK4kDbAJtaUfV57OFB2hmXB+ +tE+bhqZ8n0IiZbtvwMEoucrYTjlo/rtfdMB/TWUXkWAxgNNjLSqATq/oycQYDZn fLnZxPPSdAR1eNSB/Gwzh3Fthq2ejmVwPrS5X1F5LzS9q2l3buVhS2H1WxVllZiU j35gtHG5tBRrjwgNTEJwNkilPgKTrGXx8iQJhUQIrbjKNG72+8pgIPftqzyECj3M bCqBX8+A+WPkUBxNWcvhEhxn4xBUb+S7OlixXNOuTpMhex0LT8UGaH6sWVtOUs1j aZjUEBikSXHP/TvuRbWs1zEW2Gd6x/5Neu/By48WAag91qKpPMDF3Q7pQJO0H+sW Nlefu4Jh0PxWaugh7cRvb28lkb0fVb540/R3LiYXb49vjnUaFZGEqB2SGBcV3KeH oQHU6Ym2CWfBNeKbRuDigpqxHUQnia6+2p/UbkwwrRaNCM82VFTGG5dnpLfAvgYr ssNCRGipBclgr7QhkxU3TQj+1zMrCXkjJMT76c9QaxoulR7dDggrw9jsJH7AQYqN kBVWIZ6zzFwb4N2Hn9WZFZyXyeEvjVjl3OYN3I/QnW1wUseX/3V/xmIB8JzFffJ1 8XnTi3GEo8FqcxAlvBZc =+E7A -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/kraxel/tags/pull-ui-20161013-1' into staging ui: vnc cleanups, input-linux kbd fix. # gpg: Signature made Thu 13 Oct 2016 09:47:43 BST # gpg: using RSA key 0x4CB6D8EED3E87138 # gpg: Good signature from "Gerd Hoffmann (work) <kraxel@redhat.com>" # gpg: aka "Gerd Hoffmann <gerd@kraxel.org>" # gpg: aka "Gerd Hoffmann (private) <kraxel@gmail.com>" # Primary key fingerprint: A032 8CFF B93A 17A7 9901 FE7D 4CB6 D8EE D3E8 7138 * remotes/kraxel/tags/pull-ui-20161013-1: input-linux: initialize key state ui: rename vnc_init_state to vnc_start_protocol ui: move some initialization out of vnc_init_state ui: remove bogus call to reset_keys() in vnc_init_state ui: remove bogus call to graphic_hw_update() in vnc_listen_io ui: refactor method for setting up VncDisplay auth types ui: rename misleading 'VncDisplay' variables ui: remove 'ws_tls' field from VncState ui: remove 'enabled' and 'ws_enabled' fields from VncState ui: remove misleading comment from vnc_init_state Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
6aa5a36794
@ -347,7 +347,8 @@ static void input_linux_event(void *opaque)
|
||||
static void input_linux_complete(UserCreatable *uc, Error **errp)
|
||||
{
|
||||
InputLinux *il = INPUT_LINUX(uc);
|
||||
uint8_t evtmap, relmap, absmap, keymap[KEY_CNT / 8];
|
||||
uint8_t evtmap, relmap, absmap;
|
||||
uint8_t keymap[KEY_CNT / 8], keystate[KEY_CNT / 8];
|
||||
unsigned int i;
|
||||
int rc, ver;
|
||||
|
||||
@ -394,6 +395,7 @@ static void input_linux_complete(UserCreatable *uc, Error **errp)
|
||||
if (evtmap & (1 << EV_KEY)) {
|
||||
memset(keymap, 0, sizeof(keymap));
|
||||
rc = ioctl(il->fd, EVIOCGBIT(EV_KEY, sizeof(keymap)), keymap);
|
||||
rc = ioctl(il->fd, EVIOCGKEY(sizeof(keystate)), keystate);
|
||||
for (i = 0; i < KEY_CNT; i++) {
|
||||
if (keymap[i / 8] & (1 << (i % 8))) {
|
||||
if (linux_is_button(i)) {
|
||||
@ -401,12 +403,21 @@ static void input_linux_complete(UserCreatable *uc, Error **errp)
|
||||
} else {
|
||||
il->num_keys++;
|
||||
}
|
||||
if (keystate[i / 8] & (1 << (i % 8))) {
|
||||
il->keydown[i] = true;
|
||||
il->keycount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
qemu_set_fd_handler(il->fd, input_linux_event, NULL, il);
|
||||
input_linux_toggle_grab(il);
|
||||
if (il->keycount) {
|
||||
/* delay grab until all keys are released */
|
||||
il->grab_request = true;
|
||||
} else {
|
||||
input_linux_toggle_grab(il);
|
||||
}
|
||||
QTAILQ_INSERT_TAIL(&inputs, il, next);
|
||||
il->initialized = true;
|
||||
return;
|
||||
|
@ -92,7 +92,7 @@ static void vncws_handshake_done(Object *source,
|
||||
vnc_client_error(vs);
|
||||
} else {
|
||||
VNC_DEBUG("Websock handshake complete, starting VNC protocol\n");
|
||||
vnc_init_state(vs);
|
||||
vnc_start_protocol(vs);
|
||||
vs->ioc_tag = qio_channel_add_watch(
|
||||
vs->ioc, G_IO_IN, vnc_client_io, vs, NULL);
|
||||
}
|
||||
|
420
ui/vnc.c
420
ui/vnc.c
@ -371,7 +371,7 @@ VncInfo *qmp_query_vnc(Error **errp)
|
||||
VncDisplay *vd = vnc_display_find(NULL);
|
||||
SocketAddress *addr = NULL;
|
||||
|
||||
if (vd == NULL || !vd->enabled) {
|
||||
if (vd == NULL || !vd->lsock) {
|
||||
info->enabled = false;
|
||||
} else {
|
||||
info->enabled = true;
|
||||
@ -1222,13 +1222,13 @@ void vnc_disconnect_finish(VncState *vs)
|
||||
audio_del(vs);
|
||||
vnc_release_modifiers(vs);
|
||||
|
||||
if (vs->initialized) {
|
||||
QTAILQ_REMOVE(&vs->vd->clients, vs, next);
|
||||
if (vs->mouse_mode_notifier.notify != NULL) {
|
||||
qemu_remove_mouse_mode_change_notifier(&vs->mouse_mode_notifier);
|
||||
if (QTAILQ_EMPTY(&vs->vd->clients)) {
|
||||
/* last client gone */
|
||||
vnc_update_server_surface(vs->vd);
|
||||
}
|
||||
}
|
||||
QTAILQ_REMOVE(&vs->vd->clients, vs, next);
|
||||
if (QTAILQ_EMPTY(&vs->vd->clients)) {
|
||||
/* last client gone */
|
||||
vnc_update_server_surface(vs->vd);
|
||||
}
|
||||
|
||||
if (vs->vd->lock_key_sync)
|
||||
@ -2978,6 +2978,7 @@ static void vnc_connect(VncDisplay *vd, QIOChannelSocket *sioc,
|
||||
bool skipauth, bool websocket)
|
||||
{
|
||||
VncState *vs = g_new0(VncState, 1);
|
||||
bool first_client = QTAILQ_EMPTY(&vd->clients);
|
||||
int i;
|
||||
|
||||
vs->sioc = sioc;
|
||||
@ -3029,7 +3030,7 @@ static void vnc_connect(VncDisplay *vd, QIOChannelSocket *sioc,
|
||||
qio_channel_set_blocking(vs->ioc, false, NULL);
|
||||
if (websocket) {
|
||||
vs->websocket = 1;
|
||||
if (vd->ws_tls) {
|
||||
if (vd->tlscreds) {
|
||||
vs->ioc_tag = qio_channel_add_watch(
|
||||
vs->ioc, G_IO_IN, vncws_tls_handshake_io, vs, NULL);
|
||||
} else {
|
||||
@ -3045,26 +3046,6 @@ static void vnc_connect(VncDisplay *vd, QIOChannelSocket *sioc,
|
||||
vnc_qmp_event(vs, QAPI_EVENT_VNC_CONNECTED);
|
||||
vnc_set_share_mode(vs, VNC_SHARE_MODE_CONNECTING);
|
||||
|
||||
if (!vs->websocket) {
|
||||
vnc_init_state(vs);
|
||||
}
|
||||
|
||||
if (vd->num_connecting > vd->connections_limit) {
|
||||
QTAILQ_FOREACH(vs, &vd->clients, next) {
|
||||
if (vs->share_mode == VNC_SHARE_MODE_CONNECTING) {
|
||||
vnc_disconnect_start(vs);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void vnc_init_state(VncState *vs)
|
||||
{
|
||||
vs->initialized = true;
|
||||
VncDisplay *vd = vs->vd;
|
||||
bool first_client = QTAILQ_EMPTY(&vd->clients);
|
||||
|
||||
vs->last_x = -1;
|
||||
vs->last_y = -1;
|
||||
|
||||
@ -3083,34 +3064,45 @@ void vnc_init_state(VncState *vs)
|
||||
|
||||
graphic_hw_update(vd->dcl.con);
|
||||
|
||||
if (!vs->websocket) {
|
||||
vnc_start_protocol(vs);
|
||||
}
|
||||
|
||||
if (vd->num_connecting > vd->connections_limit) {
|
||||
QTAILQ_FOREACH(vs, &vd->clients, next) {
|
||||
if (vs->share_mode == VNC_SHARE_MODE_CONNECTING) {
|
||||
vnc_disconnect_start(vs);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void vnc_start_protocol(VncState *vs)
|
||||
{
|
||||
vnc_write(vs, "RFB 003.008\n", 12);
|
||||
vnc_flush(vs);
|
||||
vnc_read_when(vs, protocol_version, 12);
|
||||
reset_keys(vs);
|
||||
if (vs->vd->lock_key_sync)
|
||||
vs->led = qemu_add_led_event_handler(kbd_leds, vs);
|
||||
|
||||
vs->mouse_mode_notifier.notify = check_pointer_type_change;
|
||||
qemu_add_mouse_mode_change_notifier(&vs->mouse_mode_notifier);
|
||||
|
||||
/* vs might be free()ed here */
|
||||
}
|
||||
|
||||
static gboolean vnc_listen_io(QIOChannel *ioc,
|
||||
GIOCondition condition,
|
||||
void *opaque)
|
||||
{
|
||||
VncDisplay *vs = opaque;
|
||||
VncDisplay *vd = opaque;
|
||||
QIOChannelSocket *sioc = NULL;
|
||||
Error *err = NULL;
|
||||
|
||||
/* Catch-up */
|
||||
graphic_hw_update(vs->dcl.con);
|
||||
sioc = qio_channel_socket_accept(QIO_CHANNEL_SOCKET(ioc), &err);
|
||||
if (sioc != NULL) {
|
||||
qio_channel_set_delay(QIO_CHANNEL(sioc), false);
|
||||
vnc_connect(vs, sioc, false,
|
||||
ioc != QIO_CHANNEL(vs->lsock));
|
||||
vnc_connect(vd, sioc, false,
|
||||
ioc != QIO_CHANNEL(vd->lsock));
|
||||
object_unref(OBJECT(sioc));
|
||||
} else {
|
||||
/* client probably closed connection before we got there */
|
||||
@ -3133,108 +3125,108 @@ static const DisplayChangeListenerOps dcl_ops = {
|
||||
|
||||
void vnc_display_init(const char *id)
|
||||
{
|
||||
VncDisplay *vs;
|
||||
VncDisplay *vd;
|
||||
|
||||
if (vnc_display_find(id) != NULL) {
|
||||
return;
|
||||
}
|
||||
vs = g_malloc0(sizeof(*vs));
|
||||
vd = g_malloc0(sizeof(*vd));
|
||||
|
||||
vs->id = strdup(id);
|
||||
QTAILQ_INSERT_TAIL(&vnc_displays, vs, next);
|
||||
vd->id = strdup(id);
|
||||
QTAILQ_INSERT_TAIL(&vnc_displays, vd, next);
|
||||
|
||||
QTAILQ_INIT(&vs->clients);
|
||||
vs->expires = TIME_MAX;
|
||||
QTAILQ_INIT(&vd->clients);
|
||||
vd->expires = TIME_MAX;
|
||||
|
||||
if (keyboard_layout) {
|
||||
trace_vnc_key_map_init(keyboard_layout);
|
||||
vs->kbd_layout = init_keyboard_layout(name2keysym, keyboard_layout);
|
||||
vd->kbd_layout = init_keyboard_layout(name2keysym, keyboard_layout);
|
||||
} else {
|
||||
vs->kbd_layout = init_keyboard_layout(name2keysym, "en-us");
|
||||
vd->kbd_layout = init_keyboard_layout(name2keysym, "en-us");
|
||||
}
|
||||
|
||||
if (!vs->kbd_layout)
|
||||
if (!vd->kbd_layout) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
vs->share_policy = VNC_SHARE_POLICY_ALLOW_EXCLUSIVE;
|
||||
vs->connections_limit = 32;
|
||||
vd->share_policy = VNC_SHARE_POLICY_ALLOW_EXCLUSIVE;
|
||||
vd->connections_limit = 32;
|
||||
|
||||
qemu_mutex_init(&vs->mutex);
|
||||
qemu_mutex_init(&vd->mutex);
|
||||
vnc_start_worker_thread();
|
||||
|
||||
vs->dcl.ops = &dcl_ops;
|
||||
register_displaychangelistener(&vs->dcl);
|
||||
vd->dcl.ops = &dcl_ops;
|
||||
register_displaychangelistener(&vd->dcl);
|
||||
}
|
||||
|
||||
|
||||
static void vnc_display_close(VncDisplay *vs)
|
||||
static void vnc_display_close(VncDisplay *vd)
|
||||
{
|
||||
if (!vs)
|
||||
if (!vd) {
|
||||
return;
|
||||
vs->enabled = false;
|
||||
vs->is_unix = false;
|
||||
if (vs->lsock != NULL) {
|
||||
if (vs->lsock_tag) {
|
||||
g_source_remove(vs->lsock_tag);
|
||||
}
|
||||
vd->is_unix = false;
|
||||
if (vd->lsock != NULL) {
|
||||
if (vd->lsock_tag) {
|
||||
g_source_remove(vd->lsock_tag);
|
||||
}
|
||||
object_unref(OBJECT(vs->lsock));
|
||||
vs->lsock = NULL;
|
||||
object_unref(OBJECT(vd->lsock));
|
||||
vd->lsock = NULL;
|
||||
}
|
||||
vs->ws_enabled = false;
|
||||
if (vs->lwebsock != NULL) {
|
||||
if (vs->lwebsock_tag) {
|
||||
g_source_remove(vs->lwebsock_tag);
|
||||
if (vd->lwebsock != NULL) {
|
||||
if (vd->lwebsock_tag) {
|
||||
g_source_remove(vd->lwebsock_tag);
|
||||
}
|
||||
object_unref(OBJECT(vs->lwebsock));
|
||||
vs->lwebsock = NULL;
|
||||
object_unref(OBJECT(vd->lwebsock));
|
||||
vd->lwebsock = NULL;
|
||||
}
|
||||
vs->auth = VNC_AUTH_INVALID;
|
||||
vs->subauth = VNC_AUTH_INVALID;
|
||||
if (vs->tlscreds) {
|
||||
object_unparent(OBJECT(vs->tlscreds));
|
||||
vs->tlscreds = NULL;
|
||||
vd->auth = VNC_AUTH_INVALID;
|
||||
vd->subauth = VNC_AUTH_INVALID;
|
||||
if (vd->tlscreds) {
|
||||
object_unparent(OBJECT(vd->tlscreds));
|
||||
vd->tlscreds = NULL;
|
||||
}
|
||||
g_free(vs->tlsaclname);
|
||||
vs->tlsaclname = NULL;
|
||||
g_free(vd->tlsaclname);
|
||||
vd->tlsaclname = NULL;
|
||||
}
|
||||
|
||||
int vnc_display_password(const char *id, const char *password)
|
||||
{
|
||||
VncDisplay *vs = vnc_display_find(id);
|
||||
VncDisplay *vd = vnc_display_find(id);
|
||||
|
||||
if (!vs) {
|
||||
if (!vd) {
|
||||
return -EINVAL;
|
||||
}
|
||||
if (vs->auth == VNC_AUTH_NONE) {
|
||||
if (vd->auth == VNC_AUTH_NONE) {
|
||||
error_printf_unless_qmp("If you want use passwords please enable "
|
||||
"password auth using '-vnc ${dpy},password'.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
g_free(vs->password);
|
||||
vs->password = g_strdup(password);
|
||||
g_free(vd->password);
|
||||
vd->password = g_strdup(password);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vnc_display_pw_expire(const char *id, time_t expires)
|
||||
{
|
||||
VncDisplay *vs = vnc_display_find(id);
|
||||
VncDisplay *vd = vnc_display_find(id);
|
||||
|
||||
if (!vs) {
|
||||
if (!vd) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
vs->expires = expires;
|
||||
vd->expires = expires;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void vnc_display_print_local_addr(VncDisplay *vs)
|
||||
static void vnc_display_print_local_addr(VncDisplay *vd)
|
||||
{
|
||||
SocketAddress *addr;
|
||||
Error *err = NULL;
|
||||
|
||||
addr = qio_channel_socket_get_local_address(vs->lsock, &err);
|
||||
addr = qio_channel_socket_get_local_address(vd->lsock, &err);
|
||||
if (!addr) {
|
||||
return;
|
||||
}
|
||||
@ -3327,7 +3319,9 @@ static QemuOptsList qemu_vnc_opts = {
|
||||
|
||||
|
||||
static int
|
||||
vnc_display_setup_auth(VncDisplay *vs,
|
||||
vnc_display_setup_auth(int *auth,
|
||||
int *subauth,
|
||||
QCryptoTLSCreds *tlscreds,
|
||||
bool password,
|
||||
bool sasl,
|
||||
bool websocket,
|
||||
@ -3380,95 +3374,56 @@ vnc_display_setup_auth(VncDisplay *vs,
|
||||
* VNC auth mechs for plain VNC vs websockets VNC, the end
|
||||
* result has the same security characteristics.
|
||||
*/
|
||||
if (password) {
|
||||
if (vs->tlscreds) {
|
||||
vs->auth = VNC_AUTH_VENCRYPT;
|
||||
if (websocket) {
|
||||
vs->ws_tls = true;
|
||||
}
|
||||
if (object_dynamic_cast(OBJECT(vs->tlscreds),
|
||||
TYPE_QCRYPTO_TLS_CREDS_X509)) {
|
||||
VNC_DEBUG("Initializing VNC server with x509 password auth\n");
|
||||
vs->subauth = VNC_AUTH_VENCRYPT_X509VNC;
|
||||
} else if (object_dynamic_cast(OBJECT(vs->tlscreds),
|
||||
TYPE_QCRYPTO_TLS_CREDS_ANON)) {
|
||||
VNC_DEBUG("Initializing VNC server with TLS password auth\n");
|
||||
vs->subauth = VNC_AUTH_VENCRYPT_TLSVNC;
|
||||
} else {
|
||||
error_setg(errp,
|
||||
"Unsupported TLS cred type %s",
|
||||
object_get_typename(OBJECT(vs->tlscreds)));
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
if (websocket || !tlscreds) {
|
||||
if (password) {
|
||||
VNC_DEBUG("Initializing VNC server with password auth\n");
|
||||
vs->auth = VNC_AUTH_VNC;
|
||||
vs->subauth = VNC_AUTH_INVALID;
|
||||
}
|
||||
if (websocket) {
|
||||
vs->ws_auth = VNC_AUTH_VNC;
|
||||
} else {
|
||||
vs->ws_auth = VNC_AUTH_INVALID;
|
||||
}
|
||||
} else if (sasl) {
|
||||
if (vs->tlscreds) {
|
||||
vs->auth = VNC_AUTH_VENCRYPT;
|
||||
if (websocket) {
|
||||
vs->ws_tls = true;
|
||||
}
|
||||
if (object_dynamic_cast(OBJECT(vs->tlscreds),
|
||||
TYPE_QCRYPTO_TLS_CREDS_X509)) {
|
||||
VNC_DEBUG("Initializing VNC server with x509 SASL auth\n");
|
||||
vs->subauth = VNC_AUTH_VENCRYPT_X509SASL;
|
||||
} else if (object_dynamic_cast(OBJECT(vs->tlscreds),
|
||||
TYPE_QCRYPTO_TLS_CREDS_ANON)) {
|
||||
VNC_DEBUG("Initializing VNC server with TLS SASL auth\n");
|
||||
vs->subauth = VNC_AUTH_VENCRYPT_TLSSASL;
|
||||
} else {
|
||||
error_setg(errp,
|
||||
"Unsupported TLS cred type %s",
|
||||
object_get_typename(OBJECT(vs->tlscreds)));
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
*auth = VNC_AUTH_VNC;
|
||||
} else if (sasl) {
|
||||
VNC_DEBUG("Initializing VNC server with SASL auth\n");
|
||||
vs->auth = VNC_AUTH_SASL;
|
||||
vs->subauth = VNC_AUTH_INVALID;
|
||||
}
|
||||
if (websocket) {
|
||||
vs->ws_auth = VNC_AUTH_SASL;
|
||||
} else {
|
||||
vs->ws_auth = VNC_AUTH_INVALID;
|
||||
}
|
||||
} else {
|
||||
if (vs->tlscreds) {
|
||||
vs->auth = VNC_AUTH_VENCRYPT;
|
||||
if (websocket) {
|
||||
vs->ws_tls = true;
|
||||
}
|
||||
if (object_dynamic_cast(OBJECT(vs->tlscreds),
|
||||
TYPE_QCRYPTO_TLS_CREDS_X509)) {
|
||||
VNC_DEBUG("Initializing VNC server with x509 no auth\n");
|
||||
vs->subauth = VNC_AUTH_VENCRYPT_X509NONE;
|
||||
} else if (object_dynamic_cast(OBJECT(vs->tlscreds),
|
||||
TYPE_QCRYPTO_TLS_CREDS_ANON)) {
|
||||
VNC_DEBUG("Initializing VNC server with TLS no auth\n");
|
||||
vs->subauth = VNC_AUTH_VENCRYPT_TLSNONE;
|
||||
} else {
|
||||
error_setg(errp,
|
||||
"Unsupported TLS cred type %s",
|
||||
object_get_typename(OBJECT(vs->tlscreds)));
|
||||
return -1;
|
||||
}
|
||||
*auth = VNC_AUTH_SASL;
|
||||
} else {
|
||||
VNC_DEBUG("Initializing VNC server with no auth\n");
|
||||
vs->auth = VNC_AUTH_NONE;
|
||||
vs->subauth = VNC_AUTH_INVALID;
|
||||
*auth = VNC_AUTH_NONE;
|
||||
}
|
||||
if (websocket) {
|
||||
vs->ws_auth = VNC_AUTH_NONE;
|
||||
*subauth = VNC_AUTH_INVALID;
|
||||
} else {
|
||||
bool is_x509 = object_dynamic_cast(OBJECT(tlscreds),
|
||||
TYPE_QCRYPTO_TLS_CREDS_X509) != NULL;
|
||||
bool is_anon = object_dynamic_cast(OBJECT(tlscreds),
|
||||
TYPE_QCRYPTO_TLS_CREDS_ANON) != NULL;
|
||||
|
||||
if (!is_x509 && !is_anon) {
|
||||
error_setg(errp,
|
||||
"Unsupported TLS cred type %s",
|
||||
object_get_typename(OBJECT(tlscreds)));
|
||||
return -1;
|
||||
}
|
||||
*auth = VNC_AUTH_VENCRYPT;
|
||||
if (password) {
|
||||
if (is_x509) {
|
||||
VNC_DEBUG("Initializing VNC server with x509 password auth\n");
|
||||
*subauth = VNC_AUTH_VENCRYPT_X509VNC;
|
||||
} else {
|
||||
VNC_DEBUG("Initializing VNC server with TLS password auth\n");
|
||||
*subauth = VNC_AUTH_VENCRYPT_TLSVNC;
|
||||
}
|
||||
|
||||
} else if (sasl) {
|
||||
if (is_x509) {
|
||||
VNC_DEBUG("Initializing VNC server with x509 SASL auth\n");
|
||||
*subauth = VNC_AUTH_VENCRYPT_X509SASL;
|
||||
} else {
|
||||
VNC_DEBUG("Initializing VNC server with TLS SASL auth\n");
|
||||
*subauth = VNC_AUTH_VENCRYPT_TLSSASL;
|
||||
}
|
||||
} else {
|
||||
vs->ws_auth = VNC_AUTH_INVALID;
|
||||
if (is_x509) {
|
||||
VNC_DEBUG("Initializing VNC server with x509 no auth\n");
|
||||
*subauth = VNC_AUTH_VENCRYPT_X509NONE;
|
||||
} else {
|
||||
VNC_DEBUG("Initializing VNC server with TLS no auth\n");
|
||||
*subauth = VNC_AUTH_VENCRYPT_TLSNONE;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
@ -3522,7 +3477,7 @@ vnc_display_create_creds(bool x509,
|
||||
|
||||
void vnc_display_open(const char *id, Error **errp)
|
||||
{
|
||||
VncDisplay *vs = vnc_display_find(id);
|
||||
VncDisplay *vd = vnc_display_find(id);
|
||||
QemuOpts *opts = qemu_opts_find(&qemu_vnc_opts, id);
|
||||
SocketAddress *saddr = NULL, *wsaddr = NULL;
|
||||
const char *share, *device_id;
|
||||
@ -3540,12 +3495,13 @@ void vnc_display_open(const char *id, Error **errp)
|
||||
int acl = 0;
|
||||
int lock_key_sync = 1;
|
||||
int key_delay_ms;
|
||||
bool ws_enabled = false;
|
||||
|
||||
if (!vs) {
|
||||
if (!vd) {
|
||||
error_setg(errp, "VNC display not active");
|
||||
return;
|
||||
}
|
||||
vnc_display_close(vs);
|
||||
vnc_display_close(vd);
|
||||
|
||||
if (!opts) {
|
||||
return;
|
||||
@ -3575,7 +3531,7 @@ void vnc_display_open(const char *id, Error **errp)
|
||||
}
|
||||
|
||||
wsaddr = g_new0(SocketAddress, 1);
|
||||
vs->ws_enabled = true;
|
||||
ws_enabled = true;
|
||||
}
|
||||
|
||||
if (strncmp(vnc, "unix:", 5) == 0) {
|
||||
@ -3583,7 +3539,7 @@ void vnc_display_open(const char *id, Error **errp)
|
||||
saddr->u.q_unix.data = g_new0(UnixSocketAddress, 1);
|
||||
saddr->u.q_unix.data->path = g_strdup(vnc + 5);
|
||||
|
||||
if (vs->ws_enabled) {
|
||||
if (ws_enabled) {
|
||||
error_setg(errp, "UNIX sockets not supported with websock");
|
||||
goto fail;
|
||||
}
|
||||
@ -3619,7 +3575,7 @@ void vnc_display_open(const char *id, Error **errp)
|
||||
inet->ipv6 = ipv6;
|
||||
inet->has_ipv6 = has_ipv6;
|
||||
|
||||
if (vs->ws_enabled) {
|
||||
if (ws_enabled) {
|
||||
wsaddr->type = SOCKET_ADDRESS_KIND_INET;
|
||||
inet = wsaddr->u.inet.data = g_new0(InetSocketAddress, 1);
|
||||
inet->host = g_strdup(saddr->u.inet.data->host);
|
||||
@ -3686,17 +3642,17 @@ void vnc_display_open(const char *id, Error **errp)
|
||||
credid);
|
||||
goto fail;
|
||||
}
|
||||
vs->tlscreds = (QCryptoTLSCreds *)
|
||||
vd->tlscreds = (QCryptoTLSCreds *)
|
||||
object_dynamic_cast(creds,
|
||||
TYPE_QCRYPTO_TLS_CREDS);
|
||||
if (!vs->tlscreds) {
|
||||
if (!vd->tlscreds) {
|
||||
error_setg(errp, "Object with id '%s' is not TLS credentials",
|
||||
credid);
|
||||
goto fail;
|
||||
}
|
||||
object_ref(OBJECT(vs->tlscreds));
|
||||
object_ref(OBJECT(vd->tlscreds));
|
||||
|
||||
if (vs->tlscreds->endpoint != QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) {
|
||||
if (vd->tlscreds->endpoint != QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) {
|
||||
error_setg(errp,
|
||||
"Expecting TLS credentials with a server endpoint");
|
||||
goto fail;
|
||||
@ -3717,12 +3673,12 @@ void vnc_display_open(const char *id, Error **errp)
|
||||
x509verify = true;
|
||||
}
|
||||
}
|
||||
vs->tlscreds = vnc_display_create_creds(x509,
|
||||
vd->tlscreds = vnc_display_create_creds(x509,
|
||||
x509verify,
|
||||
path,
|
||||
vs->id,
|
||||
vd->id,
|
||||
errp);
|
||||
if (!vs->tlscreds) {
|
||||
if (!vd->tlscreds) {
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
@ -3732,54 +3688,62 @@ void vnc_display_open(const char *id, Error **errp)
|
||||
share = qemu_opt_get(opts, "share");
|
||||
if (share) {
|
||||
if (strcmp(share, "ignore") == 0) {
|
||||
vs->share_policy = VNC_SHARE_POLICY_IGNORE;
|
||||
vd->share_policy = VNC_SHARE_POLICY_IGNORE;
|
||||
} else if (strcmp(share, "allow-exclusive") == 0) {
|
||||
vs->share_policy = VNC_SHARE_POLICY_ALLOW_EXCLUSIVE;
|
||||
vd->share_policy = VNC_SHARE_POLICY_ALLOW_EXCLUSIVE;
|
||||
} else if (strcmp(share, "force-shared") == 0) {
|
||||
vs->share_policy = VNC_SHARE_POLICY_FORCE_SHARED;
|
||||
vd->share_policy = VNC_SHARE_POLICY_FORCE_SHARED;
|
||||
} else {
|
||||
error_setg(errp, "unknown vnc share= option");
|
||||
goto fail;
|
||||
}
|
||||
} else {
|
||||
vs->share_policy = VNC_SHARE_POLICY_ALLOW_EXCLUSIVE;
|
||||
vd->share_policy = VNC_SHARE_POLICY_ALLOW_EXCLUSIVE;
|
||||
}
|
||||
vs->connections_limit = qemu_opt_get_number(opts, "connections", 32);
|
||||
vd->connections_limit = qemu_opt_get_number(opts, "connections", 32);
|
||||
|
||||
#ifdef CONFIG_VNC_JPEG
|
||||
vs->lossy = qemu_opt_get_bool(opts, "lossy", false);
|
||||
vd->lossy = qemu_opt_get_bool(opts, "lossy", false);
|
||||
#endif
|
||||
vs->non_adaptive = qemu_opt_get_bool(opts, "non-adaptive", false);
|
||||
vd->non_adaptive = qemu_opt_get_bool(opts, "non-adaptive", false);
|
||||
/* adaptive updates are only used with tight encoding and
|
||||
* if lossy updates are enabled so we can disable all the
|
||||
* calculations otherwise */
|
||||
if (!vs->lossy) {
|
||||
vs->non_adaptive = true;
|
||||
if (!vd->lossy) {
|
||||
vd->non_adaptive = true;
|
||||
}
|
||||
|
||||
if (acl) {
|
||||
if (strcmp(vs->id, "default") == 0) {
|
||||
vs->tlsaclname = g_strdup("vnc.x509dname");
|
||||
if (strcmp(vd->id, "default") == 0) {
|
||||
vd->tlsaclname = g_strdup("vnc.x509dname");
|
||||
} else {
|
||||
vs->tlsaclname = g_strdup_printf("vnc.%s.x509dname", vs->id);
|
||||
vd->tlsaclname = g_strdup_printf("vnc.%s.x509dname", vd->id);
|
||||
}
|
||||
qemu_acl_init(vs->tlsaclname);
|
||||
qemu_acl_init(vd->tlsaclname);
|
||||
}
|
||||
#ifdef CONFIG_VNC_SASL
|
||||
if (acl && sasl) {
|
||||
char *aclname;
|
||||
|
||||
if (strcmp(vs->id, "default") == 0) {
|
||||
if (strcmp(vd->id, "default") == 0) {
|
||||
aclname = g_strdup("vnc.username");
|
||||
} else {
|
||||
aclname = g_strdup_printf("vnc.%s.username", vs->id);
|
||||
aclname = g_strdup_printf("vnc.%s.username", vd->id);
|
||||
}
|
||||
vs->sasl.acl = qemu_acl_init(aclname);
|
||||
vd->sasl.acl = qemu_acl_init(aclname);
|
||||
g_free(aclname);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (vnc_display_setup_auth(vs, password, sasl, vs->ws_enabled, errp) < 0) {
|
||||
if (vnc_display_setup_auth(&vd->auth, &vd->subauth,
|
||||
vd->tlscreds, password,
|
||||
sasl, false, errp) < 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (vnc_display_setup_auth(&vd->ws_auth, &vd->ws_subauth,
|
||||
vd->tlscreds, password,
|
||||
sasl, true, errp) < 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
@ -3790,8 +3754,8 @@ void vnc_display_open(const char *id, Error **errp)
|
||||
goto fail;
|
||||
}
|
||||
#endif
|
||||
vs->lock_key_sync = lock_key_sync;
|
||||
vs->key_delay_ms = key_delay_ms;
|
||||
vd->lock_key_sync = lock_key_sync;
|
||||
vd->key_delay_ms = key_delay_ms;
|
||||
|
||||
device_id = qemu_opt_get(opts, "display");
|
||||
if (device_id) {
|
||||
@ -3807,58 +3771,57 @@ void vnc_display_open(const char *id, Error **errp)
|
||||
con = NULL;
|
||||
}
|
||||
|
||||
if (con != vs->dcl.con) {
|
||||
unregister_displaychangelistener(&vs->dcl);
|
||||
vs->dcl.con = con;
|
||||
register_displaychangelistener(&vs->dcl);
|
||||
if (con != vd->dcl.con) {
|
||||
unregister_displaychangelistener(&vd->dcl);
|
||||
vd->dcl.con = con;
|
||||
register_displaychangelistener(&vd->dcl);
|
||||
}
|
||||
|
||||
if (reverse) {
|
||||
/* connect to viewer */
|
||||
QIOChannelSocket *sioc = NULL;
|
||||
vs->lsock = NULL;
|
||||
vs->lwebsock = NULL;
|
||||
if (vs->ws_enabled) {
|
||||
vd->lsock = NULL;
|
||||
vd->lwebsock = NULL;
|
||||
if (ws_enabled) {
|
||||
error_setg(errp, "Cannot use websockets in reverse mode");
|
||||
goto fail;
|
||||
}
|
||||
vs->is_unix = saddr->type == SOCKET_ADDRESS_KIND_UNIX;
|
||||
vd->is_unix = saddr->type == SOCKET_ADDRESS_KIND_UNIX;
|
||||
sioc = qio_channel_socket_new();
|
||||
if (qio_channel_socket_connect_sync(sioc, saddr, errp) < 0) {
|
||||
goto fail;
|
||||
}
|
||||
vnc_connect(vs, sioc, false, false);
|
||||
vnc_connect(vd, sioc, false, false);
|
||||
object_unref(OBJECT(sioc));
|
||||
} else {
|
||||
vs->lsock = qio_channel_socket_new();
|
||||
if (qio_channel_socket_listen_sync(vs->lsock, saddr, errp) < 0) {
|
||||
vd->lsock = qio_channel_socket_new();
|
||||
if (qio_channel_socket_listen_sync(vd->lsock, saddr, errp) < 0) {
|
||||
goto fail;
|
||||
}
|
||||
vs->is_unix = saddr->type == SOCKET_ADDRESS_KIND_UNIX;
|
||||
vs->enabled = true;
|
||||
vd->is_unix = saddr->type == SOCKET_ADDRESS_KIND_UNIX;
|
||||
|
||||
if (vs->ws_enabled) {
|
||||
vs->lwebsock = qio_channel_socket_new();
|
||||
if (qio_channel_socket_listen_sync(vs->lwebsock,
|
||||
if (ws_enabled) {
|
||||
vd->lwebsock = qio_channel_socket_new();
|
||||
if (qio_channel_socket_listen_sync(vd->lwebsock,
|
||||
wsaddr, errp) < 0) {
|
||||
object_unref(OBJECT(vs->lsock));
|
||||
vs->lsock = NULL;
|
||||
object_unref(OBJECT(vd->lsock));
|
||||
vd->lsock = NULL;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
vs->lsock_tag = qio_channel_add_watch(
|
||||
QIO_CHANNEL(vs->lsock),
|
||||
G_IO_IN, vnc_listen_io, vs, NULL);
|
||||
if (vs->ws_enabled) {
|
||||
vs->lwebsock_tag = qio_channel_add_watch(
|
||||
QIO_CHANNEL(vs->lwebsock),
|
||||
G_IO_IN, vnc_listen_io, vs, NULL);
|
||||
vd->lsock_tag = qio_channel_add_watch(
|
||||
QIO_CHANNEL(vd->lsock),
|
||||
G_IO_IN, vnc_listen_io, vd, NULL);
|
||||
if (ws_enabled) {
|
||||
vd->lwebsock_tag = qio_channel_add_watch(
|
||||
QIO_CHANNEL(vd->lwebsock),
|
||||
G_IO_IN, vnc_listen_io, vd, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
if (show_vnc_port) {
|
||||
vnc_display_print_local_addr(vs);
|
||||
vnc_display_print_local_addr(vd);
|
||||
}
|
||||
|
||||
qapi_free_SocketAddress(saddr);
|
||||
@ -3868,22 +3831,21 @@ void vnc_display_open(const char *id, Error **errp)
|
||||
fail:
|
||||
qapi_free_SocketAddress(saddr);
|
||||
qapi_free_SocketAddress(wsaddr);
|
||||
vs->enabled = false;
|
||||
vs->ws_enabled = false;
|
||||
ws_enabled = false;
|
||||
}
|
||||
|
||||
void vnc_display_add_client(const char *id, int csock, bool skipauth)
|
||||
{
|
||||
VncDisplay *vs = vnc_display_find(id);
|
||||
VncDisplay *vd = vnc_display_find(id);
|
||||
QIOChannelSocket *sioc;
|
||||
|
||||
if (!vs) {
|
||||
if (!vd) {
|
||||
return;
|
||||
}
|
||||
|
||||
sioc = qio_channel_socket_new_fd(csock, NULL);
|
||||
if (sioc) {
|
||||
vnc_connect(vs, sioc, skipauth, false);
|
||||
vnc_connect(vd, sioc, skipauth, false);
|
||||
object_unref(OBJECT(sioc));
|
||||
}
|
||||
}
|
||||
|
7
ui/vnc.h
7
ui/vnc.h
@ -150,7 +150,6 @@ struct VncDisplay
|
||||
guint lsock_tag;
|
||||
QIOChannelSocket *lwebsock;
|
||||
guint lwebsock_tag;
|
||||
bool ws_enabled;
|
||||
DisplaySurface *ds;
|
||||
DisplayChangeListener dcl;
|
||||
kbd_layout_t *kbd_layout;
|
||||
@ -167,14 +166,13 @@ struct VncDisplay
|
||||
|
||||
const char *id;
|
||||
QTAILQ_ENTRY(VncDisplay) next;
|
||||
bool enabled;
|
||||
bool is_unix;
|
||||
char *password;
|
||||
time_t expires;
|
||||
int auth;
|
||||
int subauth; /* Used by VeNCrypt */
|
||||
int ws_auth; /* Used by websockets */
|
||||
bool ws_tls; /* Used by websockets */
|
||||
int ws_subauth; /* Used by websockets */
|
||||
bool lossy;
|
||||
bool non_adaptive;
|
||||
QCryptoTLSCreds *tlscreds;
|
||||
@ -309,7 +307,6 @@ struct VncState
|
||||
QEMUPutLEDEntry *led;
|
||||
|
||||
bool abort;
|
||||
bool initialized;
|
||||
QemuMutex output_mutex;
|
||||
QEMUBH *bh;
|
||||
Buffer jobs_buffer;
|
||||
@ -518,7 +515,7 @@ void vnc_write_u8(VncState *vs, uint8_t value);
|
||||
void vnc_flush(VncState *vs);
|
||||
void vnc_read_when(VncState *vs, VncReadEvent *func, size_t expecting);
|
||||
void vnc_disconnect_finish(VncState *vs);
|
||||
void vnc_init_state(VncState *vs);
|
||||
void vnc_start_protocol(VncState *vs);
|
||||
|
||||
|
||||
/* Buffer I/O functions */
|
||||
|
Loading…
Reference in New Issue
Block a user