+++ /dev/null
-Index: new/qemu-options.hx
-===================================================================
---- new.orig/qemu-options.hx 2014-11-20 06:45:06.000000000 +0100
-+++ new/qemu-options.hx 2014-11-20 06:50:44.000000000 +0100
-@@ -411,6 +411,9 @@
- @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)
-Index: new/vl.c
-===================================================================
---- new.orig/vl.c 2014-11-20 06:45:06.000000000 +0100
-+++ new/vl.c 2014-11-20 06:50:44.000000000 +0100
-@@ -2730,6 +2730,7 @@
- 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;
-@@ -3477,6 +3478,14 @@
- 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
-Index: new/include/ui/console.h
-===================================================================
---- new.orig/include/ui/console.h 2014-11-20 06:45:06.000000000 +0100
-+++ new/include/ui/console.h 2014-11-20 06:50:55.000000000 +0100
-@@ -328,6 +328,7 @@
- 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);
-Index: new/ui/vnc.c
-===================================================================
---- new.orig/ui/vnc.c 2014-11-20 06:50:51.000000000 +0100
-+++ new/ui/vnc.c 2014-11-20 06:50:55.000000000 +0100
-@@ -48,6 +48,125 @@
- #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);
-
-@@ -3393,10 +3512,10 @@
- }
- if (x509) {
- VNC_DEBUG("Initializing VNC server with x509 password auth\n");
-- vs->subauth = VNC_AUTH_VENCRYPT_X509VNC;
-+ vs->subauth = VNC_AUTH_VENCRYPT_X509PLAIN;
- } else {
- VNC_DEBUG("Initializing VNC server with TLS password auth\n");
-- vs->subauth = VNC_AUTH_VENCRYPT_TLSVNC;
-+ vs->subauth = VNC_AUTH_VENCRYPT_TLSPLAIN;
- }
- } else {
- VNC_DEBUG("Initializing VNC server with password auth\n");
-@@ -3557,7 +3676,14 @@
- vs->tls.x509verify = true;
- }
- }
-- if (path) {
-+ if (path && strcmp(path, "on") == 0) {
-+ x509 = true;
-+ tls = true;
-+ if (pve_tls_set_x509_creds_dir(vs) < 0) {
-+ error_setg(errp, "No certificate path provided");
-+ goto fail;
-+ }
-+ } else if (path) {
- x509 = true;
- if (vnc_tls_set_x509_creds_dir(vs, path) < 0) {
- error_setg(errp, "Failed to find x509 certificates/keys in %s",
-Index: new/ui/vnc-auth-vencrypt.c
-===================================================================
---- new.orig/ui/vnc-auth-vencrypt.c 2014-11-20 06:45:06.000000000 +0100
-+++ new/ui/vnc-auth-vencrypt.c 2014-11-20 06:50:55.000000000 +0100
-@@ -26,6 +26,107 @@
-
- #include "vnc.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)
- {
-@@ -37,6 +138,12 @@
- 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_TLSVNC:
- case VNC_AUTH_VENCRYPT_X509VNC:
- VNC_DEBUG("Start TLS auth VNC\n");
-Index: new/ui/vnc.h
-===================================================================
---- new.orig/ui/vnc.h 2014-11-20 06:45:06.000000000 +0100
-+++ new/ui/vnc.h 2014-11-20 06:50:55.000000000 +0100
-@@ -288,6 +288,8 @@
- int auth;
- int subauth; /* Used by VeNCrypt */
- char challenge[VNC_AUTH_CHALLENGE_SIZE];
-+ int username_len;
-+ int password_len;
- #ifdef CONFIG_VNC_TLS
- VncStateTLS tls;
- #endif
-@@ -603,4 +605,6 @@
- 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 */
-Index: new/ui/vnc-tls.c
-===================================================================
---- new.orig/ui/vnc-tls.c 2014-11-20 06:45:06.000000000 +0100
-+++ new/ui/vnc-tls.c 2014-11-20 06:50:55.000000000 +0100
-@@ -302,6 +302,14 @@
-
- static int vnc_set_gnutls_priority(gnutls_session_t s, int x509)
- {
-+ /* optimize for speed */
-+ static const int ciphers[] = {
-+ GNUTLS_CIPHER_ARCFOUR_128,
-+ GNUTLS_CIPHER_AES_128_CBC,
-+ GNUTLS_CIPHER_3DES_CBC,
-+ 0
-+ };
-+
- static const int cert_types[] = { GNUTLS_CRT_X509, 0 };
- static const int protocols[] = {
- GNUTLS_TLS1_1, GNUTLS_TLS1_0, GNUTLS_SSL3, 0
-@@ -313,6 +321,11 @@
- };
- int rc;
-
-+ rc = gnutls_cipher_set_priority(s, ciphers);
-+ if (rc != GNUTLS_E_SUCCESS) {
-+ return -1;
-+ }
-+
- rc = gnutls_kx_set_priority(s, x509 ? kx_x509 : kx_anon);
- if (rc != GNUTLS_E_SUCCESS) {
- return -1;
-@@ -448,6 +460,24 @@
- return 0;
- }
-
-+int pve_tls_set_x509_creds_dir(VncDisplay *vd)
-+{
-+ if (vnc_set_x509_credential(vd, "/etc/pve", "pve-root-ca.pem", &vd->tls.x509cacert, 0) < 0)
-+ goto cleanup;
-+ if (vnc_set_x509_credential(vd, "/etc/pve/local", "pve-ssl.pem", &vd->tls.x509cert, 0) < 0)
-+ goto cleanup;
-+ if (vnc_set_x509_credential(vd, "/etc/pve/local", "pve-ssl.key", &vd->tls.x509key, 0) < 0)
-+ goto cleanup;
-+
-+ return 0;
-+
-+ cleanup:
-+ g_free(vd->tls.x509cacert);
-+ g_free(vd->tls.x509cert);
-+ g_free(vd->tls.x509key);
-+ vd->tls.x509cacert = vd->tls.x509cacrl = vd->tls.x509cert = vd->tls.x509key = NULL;
-+ return -1;
-+}
-
- int vnc_tls_set_x509_creds_dir(VncDisplay *vd,
- const char *certdir)
-Index: new/ui/vnc-tls.h
-===================================================================
---- new.orig/ui/vnc-tls.h 2014-11-20 06:45:06.000000000 +0100
-+++ new/ui/vnc-tls.h 2014-11-20 06:50:55.000000000 +0100
-@@ -61,6 +61,8 @@
-
- int vnc_tls_validate_certificate(VncState *vs);
-
-+int pve_tls_set_x509_creds_dir(VncDisplay *vd);
-+
- int vnc_tls_set_x509_creds_dir(VncDisplay *vd,
- const char *path);
-