+++ /dev/null
-From 4f24f670a0bbbce29981d7ee54d31a960e00617c Mon Sep 17 00:00:00 2001
-From: Wolfgang Bumiller <w.bumiller@proxmox.com>
-Date: Mon, 11 Jan 2016 10:40:31 +0100
-Subject: [PATCH 41/55] PVE VNC authentication
-
----
- crypto/tlscreds.c | 47 +++++++++++
- crypto/tlscredspriv.h | 2 +
- crypto/tlscredsx509.c | 13 ++--
- crypto/tlssession.c | 1 +
- include/crypto/tlscreds.h | 1 +
- include/ui/console.h | 1 +
- qemu-options.hx | 3 +
- ui/vnc-auth-vencrypt.c | 194 ++++++++++++++++++++++++++++++++++++++--------
- ui/vnc.c | 140 ++++++++++++++++++++++++++++++++-
- ui/vnc.h | 4 +
- vl.c | 9 +++
- 11 files changed, 375 insertions(+), 40 deletions(-)
-
-diff --git a/crypto/tlscreds.c b/crypto/tlscreds.c
-index 1620e12..affe020 100644
---- a/crypto/tlscreds.c
-+++ b/crypto/tlscreds.c
-@@ -158,6 +158,33 @@ qcrypto_tls_creds_prop_get_verify(Object *obj,
-
-
- static void
-+qcrypto_tls_creds_prop_set_pve(Object *obj,
-+ bool value,
-+ Error **errp G_GNUC_UNUSED)
-+{
-+ QCryptoTLSCreds *creds = QCRYPTO_TLS_CREDS(obj);
-+
-+ creds->pve = value;
-+}
-+
-+
-+static bool
-+qcrypto_tls_creds_prop_get_pve(Object *obj,
-+ Error **errp G_GNUC_UNUSED)
-+{
-+ QCryptoTLSCreds *creds = QCRYPTO_TLS_CREDS(obj);
-+
-+ return creds->pve;
-+}
-+
-+bool qcrypto_tls_creds_is_pve(QCryptoTLSCreds *creds)
-+{
-+ Error *errp = NULL;
-+ return qcrypto_tls_creds_prop_get_pve((Object*)creds, &errp);
-+}
-+
-+
-+static void
- qcrypto_tls_creds_prop_set_dir(Object *obj,
- const char *value,
- Error **errp G_GNUC_UNUSED)
-@@ -225,6 +252,26 @@ qcrypto_tls_creds_init(Object *obj)
- QCryptoTLSCreds *creds = QCRYPTO_TLS_CREDS(obj);
-
- creds->verifyPeer = true;
-+ creds->pve = false;
-+
-+ object_property_add_bool(obj, "verify-peer",
-+ qcrypto_tls_creds_prop_get_verify,
-+ qcrypto_tls_creds_prop_set_verify,
-+ NULL);
-+ object_property_add_bool(obj, "pve",
-+ qcrypto_tls_creds_prop_get_pve,
-+ qcrypto_tls_creds_prop_set_pve,
-+ NULL);
-+ object_property_add_str(obj, "dir",
-+ qcrypto_tls_creds_prop_get_dir,
-+ qcrypto_tls_creds_prop_set_dir,
-+ NULL);
-+ object_property_add_enum(obj, "endpoint",
-+ "QCryptoTLSCredsEndpoint",
-+ QCryptoTLSCredsEndpoint_lookup,
-+ qcrypto_tls_creds_prop_get_endpoint,
-+ qcrypto_tls_creds_prop_set_endpoint,
-+ NULL);
- }
-
-
-diff --git a/crypto/tlscredspriv.h b/crypto/tlscredspriv.h
-index 9222be4..3a34279 100644
---- a/crypto/tlscredspriv.h
-+++ b/crypto/tlscredspriv.h
-@@ -36,6 +36,8 @@ int qcrypto_tls_creds_get_dh_params_file(QCryptoTLSCreds *creds,
- gnutls_dh_params_t *dh_params,
- Error **errp);
-
-+bool qcrypto_tls_creds_is_pve(QCryptoTLSCreds *creds);
-+
- #endif
-
- #endif /* QCRYPTO_TLSCRED_PRIV_H__ */
-diff --git a/crypto/tlscredsx509.c b/crypto/tlscredsx509.c
-index 6a0179c..d8f3bf1 100644
---- a/crypto/tlscredsx509.c
-+++ b/crypto/tlscredsx509.c
-@@ -550,22 +550,23 @@ qcrypto_tls_creds_x509_load(QCryptoTLSCredsX509 *creds,
- *key = NULL, *dhparams = NULL;
- int ret;
- int rv = -1;
-+ bool pve = qcrypto_tls_creds_is_pve(&creds->parent_obj);
-
- trace_qcrypto_tls_creds_x509_load(creds,
- creds->parent_obj.dir ? creds->parent_obj.dir : "<nodir>");
-
- if (creds->parent_obj.endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) {
- if (qcrypto_tls_creds_get_path(&creds->parent_obj,
-- QCRYPTO_TLS_CREDS_X509_CA_CERT,
-+ pve ? "pve-root-ca.pem" : QCRYPTO_TLS_CREDS_X509_CA_CERT,
- true, &cacert, errp) < 0 ||
- qcrypto_tls_creds_get_path(&creds->parent_obj,
- QCRYPTO_TLS_CREDS_X509_CA_CRL,
- false, &cacrl, errp) < 0 ||
- qcrypto_tls_creds_get_path(&creds->parent_obj,
-- QCRYPTO_TLS_CREDS_X509_SERVER_CERT,
-+ pve ? "local/pve-ssl.pem" : QCRYPTO_TLS_CREDS_X509_SERVER_CERT,
- true, &cert, errp) < 0 ||
- qcrypto_tls_creds_get_path(&creds->parent_obj,
-- QCRYPTO_TLS_CREDS_X509_SERVER_KEY,
-+ pve ? "local/pve-ssl.key" : QCRYPTO_TLS_CREDS_X509_SERVER_KEY,
- true, &key, errp) < 0 ||
- qcrypto_tls_creds_get_path(&creds->parent_obj,
- QCRYPTO_TLS_CREDS_DH_PARAMS,
-@@ -574,13 +575,13 @@ qcrypto_tls_creds_x509_load(QCryptoTLSCredsX509 *creds,
- }
- } else {
- if (qcrypto_tls_creds_get_path(&creds->parent_obj,
-- QCRYPTO_TLS_CREDS_X509_CA_CERT,
-+ pve ? "pve-root-ca.pem" : QCRYPTO_TLS_CREDS_X509_CA_CERT,
- true, &cacert, errp) < 0 ||
- qcrypto_tls_creds_get_path(&creds->parent_obj,
-- QCRYPTO_TLS_CREDS_X509_CLIENT_CERT,
-+ pve ? "local/pve-ssl.pem" : QCRYPTO_TLS_CREDS_X509_CLIENT_CERT,
- false, &cert, errp) < 0 ||
- qcrypto_tls_creds_get_path(&creds->parent_obj,
-- QCRYPTO_TLS_CREDS_X509_CLIENT_KEY,
-+ pve ? "local/pve-ssl.key" : QCRYPTO_TLS_CREDS_X509_CLIENT_KEY,
- false, &key, errp) < 0) {
- goto cleanup;
- }
-diff --git a/crypto/tlssession.c b/crypto/tlssession.c
-index a543e5a..564ad5d 100644
---- a/crypto/tlssession.c
-+++ b/crypto/tlssession.c
-@@ -23,6 +23,7 @@
- #include "crypto/tlscredsanon.h"
- #include "crypto/tlscredsx509.h"
- #include "qapi/error.h"
-+#include "crypto/tlscredspriv.h"
- #include "qemu/acl.h"
- #include "trace.h"
-
-diff --git a/include/crypto/tlscreds.h b/include/crypto/tlscreds.h
-index 8e2babd..8969e66 100644
---- a/include/crypto/tlscreds.h
-+++ b/include/crypto/tlscreds.h
-@@ -54,6 +54,7 @@ struct QCryptoTLSCreds {
- gnutls_dh_params_t dh_params;
- #endif
- bool verifyPeer;
-+ bool pve;
- };
-
-
-diff --git a/include/ui/console.h b/include/ui/console.h
-index d5a88d9..c17bee0 100644
---- a/include/ui/console.h
-+++ b/include/ui/console.h
-@@ -427,6 +427,7 @@ void sdl_display_init(DisplayState *ds, int full_screen, int no_frame);
- void cocoa_display_init(DisplayState *ds, int full_screen);
-
- /* vnc.c */
-+void pve_auth_setup(int vmid);
- void vnc_display_init(const char *id);
- void vnc_display_open(const char *id, Error **errp);
- void vnc_display_add_client(const char *id, int csock, bool skipauth);
-diff --git a/qemu-options.hx b/qemu-options.hx
-index 20ab9ac..30b90f5 100644
---- a/qemu-options.hx
-+++ b/qemu-options.hx
-@@ -476,6 +476,9 @@ STEXI
- @table @option
- ETEXI
-
-+DEF("id", HAS_ARG, QEMU_OPTION_id,
-+ "-id n set the VMID\n", QEMU_ARCH_ALL)
-+
- DEF("fda", HAS_ARG, QEMU_OPTION_fda,
- "-fda/-fdb file use 'file' as floppy disk 0/1 image\n", QEMU_ARCH_ALL)
- DEF("fdb", HAS_ARG, QEMU_OPTION_fdb, "", QEMU_ARCH_ALL)
-diff --git a/ui/vnc-auth-vencrypt.c b/ui/vnc-auth-vencrypt.c
-index 11c8c9a..d11f1df 100644
---- a/ui/vnc-auth-vencrypt.c
-+++ b/ui/vnc-auth-vencrypt.c
-@@ -28,6 +28,107 @@
- #include "vnc.h"
- #include "qapi/error.h"
- #include "qemu/main-loop.h"
-+#include "qemu/sockets.h"
-+
-+static int protocol_client_auth_plain(VncState *vs, uint8_t *data, size_t len)
-+{
-+ const char *err = NULL;
-+ char username[256];
-+ char passwd[512];
-+
-+ char clientip[256];
-+ clientip[0] = 0;
-+ struct sockaddr_in client;
-+ socklen_t addrlen = sizeof(client);
-+ if (getpeername(vs->csock, &client, &addrlen) == 0) {
-+ inet_ntop(client.sin_family, &client.sin_addr,
-+ clientip, sizeof(clientip));
-+ }
-+
-+ if ((len != (vs->username_len + vs->password_len)) ||
-+ (vs->username_len >= (sizeof(username)-1)) ||
-+ (vs->password_len >= (sizeof(passwd)-1)) ) {
-+ err = "Got unexpected data length";
-+ goto err;
-+ }
-+
-+ strncpy(username, (char *)data, vs->username_len);
-+ username[vs->username_len] = 0;
-+ strncpy(passwd, (char *)data + vs->username_len, vs->password_len);
-+ passwd[vs->password_len] = 0;
-+
-+ VNC_DEBUG("AUTH PLAIN username: %s pw: %s\n", username, passwd);
-+
-+ if (pve_auth_verify(clientip, username, passwd) == 0) {
-+ vnc_write_u32(vs, 0); /* Accept auth completion */
-+ start_client_init(vs);
-+ return 0;
-+ }
-+
-+ err = "Authentication failed";
-+err:
-+ if (err) {
-+ VNC_DEBUG("AUTH PLAIN ERROR: %s\n", err);
-+ vnc_write_u32(vs, 1); /* Reject auth */
-+ if (vs->minor >= 8) {
-+ int elen = strlen(err);
-+ vnc_write_u32(vs, elen);
-+ vnc_write(vs, err, elen);
-+ }
-+ }
-+ vnc_flush(vs);
-+ vnc_client_error(vs);
-+
-+ return 0;
-+
-+}
-+
-+static int protocol_client_auth_plain_start(VncState *vs, uint8_t *data, size_t len)
-+{
-+ uint32_t ulen = read_u32(data, 0);
-+ uint32_t pwlen = read_u32(data, 4);
-+ const char *err = NULL;
-+
-+ VNC_DEBUG("AUTH PLAIN START %u %u\n", ulen, pwlen);
-+
-+ if (!ulen) {
-+ err = "No User name.";
-+ goto err;
-+ }
-+ if (ulen >= 255) {
-+ err = "User name too long.";
-+ goto err;
-+ }
-+ if (!pwlen) {
-+ err = "Password too short";
-+ goto err;
-+ }
-+ if (pwlen >= 511) {
-+ err = "Password too long.";
-+ goto err;
-+ }
-+
-+ vs->username_len = ulen;
-+ vs->password_len = pwlen;
-+
-+ vnc_read_when(vs, protocol_client_auth_plain, ulen + pwlen);
-+
-+ return 0;
-+err:
-+ if (err) {
-+ VNC_DEBUG("AUTH PLAIN ERROR: %s\n", err);
-+ vnc_write_u32(vs, 1); /* Reject auth */
-+ if (vs->minor >= 8) {
-+ int elen = strlen(err);
-+ vnc_write_u32(vs, elen);
-+ vnc_write(vs, err, elen);
-+ }
-+ }
-+ vnc_flush(vs);
-+ vnc_client_error(vs);
-+
-+ return 0;
-+}
-
- static void start_auth_vencrypt_subauth(VncState *vs)
- {
-@@ -39,6 +140,17 @@ static void start_auth_vencrypt_subauth(VncState *vs)
- start_client_init(vs);
- break;
-
-+ case VNC_AUTH_VENCRYPT_TLSPLAIN:
-+ case VNC_AUTH_VENCRYPT_X509PLAIN:
-+ VNC_DEBUG("Start TLS auth PLAIN\n");
-+ vnc_read_when(vs, protocol_client_auth_plain_start, 8);
-+ break;
-+
-+ case VNC_AUTH_VENCRYPT_PLAIN:
-+ VNC_DEBUG("Start auth PLAIN\n");
-+ vnc_read_when(vs, protocol_client_auth_plain_start, 8);
-+ break;
-+
- case VNC_AUTH_VENCRYPT_TLSVNC:
- case VNC_AUTH_VENCRYPT_X509VNC:
- VNC_DEBUG("Start TLS auth VNC\n");
-@@ -87,44 +199,63 @@ static int protocol_client_vencrypt_auth(VncState *vs, uint8_t *data, size_t len
- {
- int auth = read_u32(data, 0);
-
-- if (auth != vs->subauth) {
-+ if (auth != vs->subauth && auth != VNC_AUTH_VENCRYPT_PLAIN) {
- VNC_DEBUG("Rejecting auth %d\n", auth);
- vnc_write_u8(vs, 0); /* Reject auth */
- vnc_flush(vs);
- vnc_client_error(vs);
- } else {
-- Error *err = NULL;
-- QIOChannelTLS *tls;
-- VNC_DEBUG("Accepting auth %d, setting up TLS for handshake\n", auth);
-- vnc_write_u8(vs, 1); /* Accept auth */
-- vnc_flush(vs);
--
-- if (vs->ioc_tag) {
-- g_source_remove(vs->ioc_tag);
-- vs->ioc_tag = 0;
-+ if (auth == VNC_AUTH_VENCRYPT_PLAIN) {
-+ vs->subauth = auth;
-+ start_auth_vencrypt_subauth(vs);
- }
-+ else
-+ {
-+ Error *err = NULL;
-+ QIOChannelTLS *tls;
-+ VNC_DEBUG("Accepting auth %d, setting up TLS for handshake\n", auth);
-+ vnc_write_u8(vs, 1); /* Accept auth */
-+ vnc_flush(vs);
-
-- tls = qio_channel_tls_new_server(
-- vs->ioc,
-- vs->vd->tlscreds,
-- vs->vd->tlsaclname,
-- &err);
-- if (!tls) {
-- VNC_DEBUG("Failed to setup TLS %s\n", error_get_pretty(err));
-- error_free(err);
-- vnc_client_error(vs);
-- return 0;
-- }
-+ if (vs->ioc_tag) {
-+ g_source_remove(vs->ioc_tag);
-+ vs->ioc_tag = 0;
-+ }
-
-- VNC_DEBUG("Start TLS VeNCrypt handshake process\n");
-- object_unref(OBJECT(vs->ioc));
-- vs->ioc = QIO_CHANNEL(tls);
-- vs->tls = qio_channel_tls_get_session(tls);
-+ tls = qio_channel_tls_new_server(
-+ vs->ioc,
-+ vs->vd->tlscreds,
-+ vs->vd->tlsaclname,
-+ &err);
-+ if (!tls) {
-+ VNC_DEBUG("Failed to setup TLS %s\n", error_get_pretty(err));
-+ error_free(err);
-+ vnc_client_error(vs);
-+ return 0;
-+ vs->tls = qcrypto_tls_session_new(vs->vd->tlscreds,
-+ NULL,
-+ vs->vd->tlsaclname,
-+ QCRYPTO_TLS_CREDS_ENDPOINT_SERVER,
-+ &err);
-+ if (!vs->tls) {
-+ VNC_DEBUG("Failed to setup TLS %s\n",
-+ error_get_pretty(err));
-+ error_free(err);
-+ vnc_client_error(vs);
-+ return 0;
-+ }
-+ }
-
-- qio_channel_tls_handshake(tls,
-- vnc_tls_handshake_done,
-- vs,
-- NULL);
-+ VNC_DEBUG("Start TLS VeNCrypt handshake process\n");
-+ object_unref(OBJECT(vs->ioc));
-+ vs->ioc = QIO_CHANNEL(tls);
-+ vs->tls = qio_channel_tls_get_session(tls);
-+
-+ qio_channel_tls_handshake(tls,
-+ vnc_tls_handshake_done,
-+ vs,
-+ NULL);
-+ }
- }
- return 0;
- }
-@@ -138,10 +269,11 @@ static int protocol_client_vencrypt_init(VncState *vs, uint8_t *data, size_t len
- vnc_flush(vs);
- vnc_client_error(vs);
- } else {
-- VNC_DEBUG("Sending allowed auth %d\n", vs->subauth);
-+ VNC_DEBUG("Sending allowed auths %d %d\n", vs->subauth, VNC_AUTH_VENCRYPT_PLAIN);
- vnc_write_u8(vs, 0); /* Accept version */
-- vnc_write_u8(vs, 1); /* Number of sub-auths */
-+ vnc_write_u8(vs, 2); /* Number of sub-auths */
- vnc_write_u32(vs, vs->subauth); /* The supported auth */
-+ vnc_write_u32(vs, VNC_AUTH_VENCRYPT_PLAIN); /* Alternative supported auth */
- vnc_flush(vs);
- vnc_read_when(vs, protocol_client_vencrypt_auth, 4);
- }
-diff --git a/ui/vnc.c b/ui/vnc.c
-index 4610ce8..66e2163 100644
---- a/ui/vnc.c
-+++ b/ui/vnc.c
-@@ -55,6 +55,125 @@ static const struct timeval VNC_REFRESH_LOSSY = { 2, 0 };
- #include "vnc_keysym.h"
- #include "crypto/cipher.h"
-
-+static int pve_vmid = 0;
-+
-+void pve_auth_setup(int vmid) {
-+ pve_vmid = vmid;
-+}
-+
-+static char *
-+urlencode(char *buf, const char *value)
-+{
-+ static const char *hexchar = "0123456789abcdef";
-+ char *p = buf;
-+ int i;
-+ int l = strlen(value);
-+ for (i = 0; i < l; i++) {
-+ char c = value[i];
-+ if (('a' <= c && c <= 'z') ||
-+ ('A' <= c && c <= 'Z') ||
-+ ('0' <= c && c <= '9')) {
-+ *p++ = c;
-+ } else if (c == 32) {
-+ *p++ = '+';
-+ } else {
-+ *p++ = '%';
-+ *p++ = hexchar[c >> 4];
-+ *p++ = hexchar[c & 15];
-+ }
-+ }
-+ *p = 0;
-+
-+ return p;
-+}
-+
-+int
-+pve_auth_verify(const char *clientip, const char *username, const char *passwd)
-+{
-+ struct sockaddr_in server;
-+
-+ int sfd = socket(AF_INET, SOCK_STREAM, 0);
-+ if (sfd == -1) {
-+ perror("pve_auth_verify: socket failed");
-+ return -1;
-+ }
-+
-+ struct hostent *he;
-+ if ((he = gethostbyname("localhost")) == NULL) {
-+ fprintf(stderr, "pve_auth_verify: error resolving hostname\n");
-+ goto err;
-+ }
-+
-+ memcpy(&server.sin_addr, he->h_addr_list[0], he->h_length);
-+ server.sin_family = AF_INET;
-+ server.sin_port = htons(85);
-+
-+ if (connect(sfd, (struct sockaddr *)&server, sizeof(server))) {
-+ perror("pve_auth_verify: error connecting to server");
-+ goto err;
-+ }
-+
-+ char buf[8192];
-+ char form[8192];
-+
-+ char *p = form;
-+ p = urlencode(p, "username");
-+ *p++ = '=';
-+ p = urlencode(p, username);
-+
-+ *p++ = '&';
-+ p = urlencode(p, "password");
-+ *p++ = '=';
-+ p = urlencode(p, passwd);
-+
-+ *p++ = '&';
-+ p = urlencode(p, "path");
-+ *p++ = '=';
-+ char authpath[256];
-+ sprintf(authpath, "/vms/%d", pve_vmid);
-+ p = urlencode(p, authpath);
-+
-+ *p++ = '&';
-+ p = urlencode(p, "privs");
-+ *p++ = '=';
-+ p = urlencode(p, "VM.Console");
-+
-+ sprintf(buf, "POST /api2/json/access/ticket HTTP/1.1\n"
-+ "Host: localhost:85\n"
-+ "Connection: close\n"
-+ "PVEClientIP: %s\n"
-+ "Content-Type: application/x-www-form-urlencoded\n"
-+ "Content-Length: %zd\n\n%s\n", clientip, strlen(form), form);
-+ ssize_t len = strlen(buf);
-+ ssize_t sb = send(sfd, buf, len, 0);
-+ if (sb < 0) {
-+ perror("pve_auth_verify: send failed");
-+ goto err;
-+ }
-+ if (sb != len) {
-+ fprintf(stderr, "pve_auth_verify: partial send error\n");
-+ goto err;
-+ }
-+
-+ len = recv(sfd, buf, sizeof(buf) - 1, 0);
-+ if (len < 0) {
-+ perror("pve_auth_verify: recv failed");
-+ goto err;
-+ }
-+
-+ buf[len] = 0;
-+
-+ //printf("DATA:%s\n", buf);
-+
-+ shutdown(sfd, SHUT_RDWR);
-+
-+ return strncmp(buf, "HTTP/1.1 200 OK", 15);
-+
-+err:
-+ shutdown(sfd, SHUT_RDWR);
-+ return -1;
-+}
-+
- static QTAILQ_HEAD(, VncDisplay) vnc_displays =
- QTAILQ_HEAD_INITIALIZER(vnc_displays);
-
-@@ -3359,11 +3478,17 @@ vnc_display_setup_auth(VncDisplay *vs,
- 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;
-+ if (vs->tlscreds->pve)
-+ vs->subauth = VNC_AUTH_VENCRYPT_X509PLAIN;
-+ else
-+ 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;
-+ if (vs->tlscreds->pve)
-+ vs->subauth = VNC_AUTH_VENCRYPT_TLSPLAIN;
-+ else
-+ vs->subauth = VNC_AUTH_VENCRYPT_TLSVNC;
- } else {
- error_setg(errp,
- "Unsupported TLS cred type %s",
-@@ -3454,6 +3579,7 @@ vnc_display_create_creds(bool x509,
- bool x509verify,
- const char *dir,
- const char *id,
-+ bool pve,
- Error **errp)
- {
- gchar *credsid = g_strdup_printf("tlsvnc%s", id);
-@@ -3469,6 +3595,7 @@ vnc_display_create_creds(bool x509,
- "endpoint", "server",
- "dir", dir,
- "verify-peer", x509verify ? "yes" : "no",
-+ "pve", pve ? "yes" : "no",
- NULL);
- } else {
- creds = object_new_with_props(TYPE_QCRYPTO_TLS_CREDS_ANON,
-@@ -3476,6 +3603,7 @@ vnc_display_create_creds(bool x509,
- credsid,
- &err,
- "endpoint", "server",
-+ "pve", pve ? "yes" : "no",
- NULL);
- }
-
-@@ -3669,12 +3797,17 @@ void vnc_display_open(const char *id, Error **errp)
- }
- } else {
- const char *path;
-- bool tls = false, x509 = false, x509verify = false;
-+ bool tls = false, x509 = false, x509verify = false, pve = false;
- tls = qemu_opt_get_bool(opts, "tls", false);
- path = qemu_opt_get(opts, "x509");
- if (tls || path) {
- if (path) {
- x509 = true;
-+ if (!strcmp(path, "on")) {
-+ /* magic to default to /etc/pve */
-+ path = "/etc/pve";
-+ pve = true;
-+ }
- } else {
- path = qemu_opt_get(opts, "x509verify");
- if (path) {
-@@ -3686,6 +3819,7 @@ void vnc_display_open(const char *id, Error **errp)
- x509verify,
- path,
- vs->id,
-+ pve,
- errp);
- if (!vs->tlscreds) {
- goto fail;
-diff --git a/ui/vnc.h b/ui/vnc.h
-index 81a3261..40e2780 100644
---- a/ui/vnc.h
-+++ b/ui/vnc.h
-@@ -281,6 +281,8 @@ struct VncState
- int auth;
- int subauth; /* Used by VeNCrypt */
- char challenge[VNC_AUTH_CHALLENGE_SIZE];
-+ int username_len;
-+ int password_len;
- QCryptoTLSSession *tls; /* Borrowed pointer from channel, don't free */
- #ifdef CONFIG_VNC_SASL
- VncStateSASL sasl;
-@@ -576,4 +578,6 @@ int vnc_zrle_send_framebuffer_update(VncState *vs, int x, int y, int w, int h);
- int vnc_zywrle_send_framebuffer_update(VncState *vs, int x, int y, int w, int h);
- void vnc_zrle_clear(VncState *vs);
-
-+int pve_auth_verify(const char *clientip, const char *username, const char *passwd);
-+
- #endif /* __QEMU_VNC_H */
-diff --git a/vl.c b/vl.c
-index f393767..f5fc86f 100644
---- a/vl.c
-+++ b/vl.c
-@@ -2967,6 +2967,7 @@ static void set_memory_options(uint64_t *ram_slots, ram_addr_t *maxram_size,
- int main(int argc, char **argv, char **envp)
- {
- int i;
-+ long int vm_id_long = 0;
- int snapshot, linux_boot;
- const char *initrd_filename;
- const char *kernel_filename, *kernel_cmdline;
-@@ -3737,6 +3738,14 @@ int main(int argc, char **argv, char **envp)
- exit(1);
- }
- break;
-+ case QEMU_OPTION_id:
-+ vm_id_long = strtol(optarg, (char **) &optarg, 10);
-+ if (*optarg != 0 || vm_id_long < 100 || vm_id_long > INT_MAX) {
-+ fprintf(stderr, "Invalid ID\n");
-+ exit(1);
-+ }
-+ pve_auth_setup(vm_id_long);
-+ break;
- case QEMU_OPTION_vnc:
- {
- #ifdef CONFIG_VNC
---
-2.1.4
-