diff --git a/.cvsignore b/.cvsignore index 53c87a3..97f3c02 100644 --- a/.cvsignore +++ b/.cvsignore @@ -1 +1 @@ -qemu-kvm-0.10.tar.gz +qemu-kvm-*.tar.gz diff --git a/01-tls-handshake-fix.patch b/01-tls-handshake-fix.patch deleted file mode 100644 index 112c4fe..0000000 --- a/01-tls-handshake-fix.patch +++ /dev/null @@ -1,19 +0,0 @@ -Index: qemu-kvm-0.10/qemu/vnc.c -=================================================================== ---- qemu-kvm-0.10.orig/qemu/vnc.c -+++ qemu-kvm-0.10/qemu/vnc.c -@@ -2096,14 +2096,6 @@ static int protocol_client_vencrypt_auth - VNC_DEBUG("Failed to complete TLS\n"); - return 0; - } -- -- if (vs->wiremode == VNC_WIREMODE_TLS) { -- VNC_DEBUG("Starting VeNCrypt subauth\n"); -- return start_auth_vencrypt_subauth(vs); -- } else { -- VNC_DEBUG("TLS handshake blocked\n"); -- return 0; -- } - } - return 0; - } diff --git a/02-vnc-monitor-info.patch b/02-vnc-monitor-info.patch deleted file mode 100644 index 04a3988..0000000 --- a/02-vnc-monitor-info.patch +++ /dev/null @@ -1,152 +0,0 @@ -Index: qemu-kvm-0.10/qemu/vnc.c -=================================================================== ---- qemu-kvm-0.10.orig/qemu/vnc.c -+++ qemu-kvm-0.10/qemu/vnc.c -@@ -166,19 +166,136 @@ struct VncState - static VncDisplay *vnc_display; /* needed for info vnc */ - static DisplayChangeListener *dcl; - -+static char *addr_to_string(const char *format, -+ struct sockaddr_storage *sa, -+ socklen_t salen) { -+ char *addr; -+ char host[NI_MAXHOST]; -+ char serv[NI_MAXSERV]; -+ int err; -+ -+ if ((err = getnameinfo((struct sockaddr *)sa, salen, -+ host, sizeof(host), -+ serv, sizeof(serv), -+ NI_NUMERICHOST | NI_NUMERICSERV)) != 0) { -+ VNC_DEBUG("Cannot resolve address %d: %s\n", -+ err, gai_strerror(err)); -+ return NULL; -+ } -+ -+ if (asprintf(&addr, format, host, serv) < 0) -+ return NULL; -+ -+ return addr; -+} -+ -+static char *vnc_socket_local_addr(const char *format, int fd) { -+ struct sockaddr_storage sa; -+ socklen_t salen; -+ -+ salen = sizeof(sa); -+ if (getsockname(fd, (struct sockaddr*)&sa, &salen) < 0) -+ return NULL; -+ -+ return addr_to_string(format, &sa, salen); -+} -+ -+static char *vnc_socket_remote_addr(const char *format, int fd) { -+ struct sockaddr_storage sa; -+ socklen_t salen; -+ -+ salen = sizeof(sa); -+ if (getpeername(fd, (struct sockaddr*)&sa, &salen) < 0) -+ return NULL; -+ -+ return addr_to_string(format, &sa, salen); -+} -+ -+static const char *vnc_auth_name(VncDisplay *vd) { -+ switch (vd->auth) { -+ case VNC_AUTH_INVALID: -+ return "invalid"; -+ case VNC_AUTH_NONE: -+ return "none"; -+ case VNC_AUTH_VNC: -+ return "vnc"; -+ case VNC_AUTH_RA2: -+ return "ra2"; -+ case VNC_AUTH_RA2NE: -+ return "ra2ne"; -+ case VNC_AUTH_TIGHT: -+ return "tight"; -+ case VNC_AUTH_ULTRA: -+ return "ultra"; -+ case VNC_AUTH_TLS: -+ return "tls"; -+ case VNC_AUTH_VENCRYPT: -+#ifdef CONFIG_VNC_TLS -+ switch (vd->subauth) { -+ case VNC_AUTH_VENCRYPT_PLAIN: -+ return "vencrypt+plain"; -+ case VNC_AUTH_VENCRYPT_TLSNONE: -+ return "vencrypt+tls+none"; -+ case VNC_AUTH_VENCRYPT_TLSVNC: -+ return "vencrypt+tls+vnc"; -+ case VNC_AUTH_VENCRYPT_TLSPLAIN: -+ return "vencrypt+tls+plain"; -+ case VNC_AUTH_VENCRYPT_X509NONE: -+ return "vencrypt+x509+none"; -+ case VNC_AUTH_VENCRYPT_X509VNC: -+ return "vencrypt+x509+vnc"; -+ case VNC_AUTH_VENCRYPT_X509PLAIN: -+ return "vencrypt+x509+plain"; -+ default: -+ return "vencrypt"; -+ } -+#else -+ return "vencrypt"; -+#endif -+ } -+ return "unknown"; -+} -+ -+#define VNC_SOCKET_FORMAT_PRETTY "local %s:%s" -+ -+static void do_info_vnc_client(VncState *client) -+{ -+ char *clientAddr = -+ vnc_socket_remote_addr(" address: %s:%s\n", -+ client->csock); -+ if (!clientAddr) -+ return; -+ -+ term_puts("Client:\n"); -+ term_puts(clientAddr); -+ free(clientAddr); -+} -+ - void do_info_vnc(void) - { -- if (vnc_display == NULL || vnc_display->display == NULL) -- term_printf("VNC server disabled\n"); -- else { -- term_printf("VNC server active on: "); -- term_print_filename(vnc_display->display); -- term_printf("\n"); -- -- if (vnc_display->clients == NULL) -- term_printf("No client connected\n"); -- else -- term_printf("Client connected\n"); -+ if (vnc_display == NULL || vnc_display->display == NULL) { -+ term_printf("Server: disabled\n"); -+ } else { -+ char *serverAddr = vnc_socket_local_addr(" address: %s:%s\n", -+ vnc_display->lsock); -+ -+ if (!serverAddr) -+ return; -+ -+ term_puts("Server:\n"); -+ term_puts(serverAddr); -+ free(serverAddr); -+ term_printf(" auth: %s\n", vnc_auth_name(vnc_display)); -+ -+ if (vnc_display->clients) { -+ VncState *client = vnc_display->clients; -+ while (client) { -+ do_info_vnc_client(client); -+ client = client->next; -+ } -+ } else { -+ term_printf("Client: none\n"); -+ } - } - } - diff --git a/03-display-keymaps.patch b/03-display-keymaps.patch deleted file mode 100644 index 6819d74..0000000 --- a/03-display-keymaps.patch +++ /dev/null @@ -1,330 +0,0 @@ -Index: qemu-kvm-0.10/qemu/Makefile -=================================================================== ---- qemu-kvm-0.10.orig/qemu/Makefile -+++ qemu-kvm-0.10/qemu/Makefile -@@ -141,6 +141,7 @@ endif - AUDIO_OBJS+= wavcapture.o - OBJS+=$(addprefix audio/, $(AUDIO_OBJS)) - -+OBJS+=keymaps.o - ifdef CONFIG_SDL - OBJS+=sdl.o x_keymap.o - endif -@@ -165,15 +166,17 @@ LIBS+=$(VDE_LIBS) - - cocoa.o: cocoa.m - --sdl.o: sdl.c keymaps.c sdl_keysym.h -+keymaps.o: keymaps.c keymaps.h -+ -+sdl.o: sdl.c keymaps.h sdl_keysym.h - - sdl.o audio/sdlaudio.o: CFLAGS += $(SDL_CFLAGS) - --vnc.o: vnc.c keymaps.c sdl_keysym.h vnchextile.h d3des.c d3des.h -+vnc.o: vnc.c keymaps.h sdl_keysym.h vnchextile.h d3des.c d3des.h - - vnc.o: CFLAGS += $(CONFIG_VNC_TLS_CFLAGS) - --curses.o: curses.c keymaps.c curses_keys.h -+curses.o: curses.c keymaps.h curses_keys.h - - bt-host.o: CFLAGS += $(CONFIG_BLUEZ_CFLAGS) - -Index: qemu-kvm-0.10/qemu/curses.c -=================================================================== ---- qemu-kvm-0.10.orig/qemu/curses.c -+++ qemu-kvm-0.10/qemu/curses.c -@@ -158,7 +158,6 @@ static void curses_cursor_position(Displ - /* generic keyboard conversion */ - - #include "curses_keys.h" --#include "keymaps.c" - - static kbd_layout_t *kbd_layout = 0; - static int keycode2keysym[CURSES_KEYS]; -@@ -311,7 +310,7 @@ static void curses_keyboard_setup(void) - keyboard_layout = "en-us"; - #endif - if(keyboard_layout) { -- kbd_layout = init_keyboard_layout(keyboard_layout); -+ kbd_layout = init_keyboard_layout(name2keysym, keyboard_layout); - if (!kbd_layout) - exit(1); - } -Index: qemu-kvm-0.10/qemu/curses_keys.h -=================================================================== ---- qemu-kvm-0.10.orig/qemu/curses_keys.h -+++ qemu-kvm-0.10/qemu/curses_keys.h -@@ -21,6 +21,10 @@ - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -+ -+#include "keymaps.h" -+ -+ - #define KEY_RELEASE 0x80 - #define KEY_MASK 0x7f - #define SHIFT_CODE 0x2a -@@ -239,11 +243,6 @@ static const int curses2keysym[CURSES_KE - - }; - --typedef struct { -- const char* name; -- int keysym; --} name2keysym_t; -- - static const name2keysym_t name2keysym[] = { - /* Plain ASCII */ - { "space", 0x020 }, -Index: qemu-kvm-0.10/qemu/keymaps.c -=================================================================== ---- qemu-kvm-0.10.orig/qemu/keymaps.c -+++ qemu-kvm-0.10/qemu/keymaps.c -@@ -22,34 +22,20 @@ - * THE SOFTWARE. - */ - --static int get_keysym(const char *name) -+#include "keymaps.h" -+#include "sysemu.h" -+ -+static int get_keysym(const name2keysym_t *table, -+ const char *name) - { - const name2keysym_t *p; -- for(p = name2keysym; p->name != NULL; p++) { -+ for(p = table; p->name != NULL; p++) { - if (!strcmp(p->name, name)) - return p->keysym; - } - return 0; - } - --struct key_range { -- int start; -- int end; -- struct key_range *next; --}; -- --#define MAX_NORMAL_KEYCODE 512 --#define MAX_EXTRA_COUNT 256 --typedef struct { -- uint16_t keysym2keycode[MAX_NORMAL_KEYCODE]; -- struct { -- int keysym; -- uint16_t keycode; -- } keysym2keycode_extra[MAX_EXTRA_COUNT]; -- int extra_count; -- struct key_range *keypad_range; -- struct key_range *numlock_range; --} kbd_layout_t; - - static void add_to_key_range(struct key_range **krp, int code) { - struct key_range *kr; -@@ -73,7 +59,8 @@ static void add_to_key_range(struct key_ - } - } - --static kbd_layout_t *parse_keyboard_layout(const char *language, -+static kbd_layout_t *parse_keyboard_layout(const name2keysym_t *table, -+ const char *language, - kbd_layout_t * k) - { - FILE *f; -@@ -102,7 +89,7 @@ static kbd_layout_t *parse_keyboard_layo - if (!strncmp(line, "map ", 4)) - continue; - if (!strncmp(line, "include ", 8)) { -- parse_keyboard_layout(line + 8, k); -+ parse_keyboard_layout(table, line + 8, k); - } else { - char *end_of_keysym = line; - while (*end_of_keysym != 0 && *end_of_keysym != ' ') -@@ -110,7 +97,7 @@ static kbd_layout_t *parse_keyboard_layo - if (*end_of_keysym) { - int keysym; - *end_of_keysym = 0; -- keysym = get_keysym(line); -+ keysym = get_keysym(table, line); - if (keysym == 0) { - // fprintf(stderr, "Warning: unknown keysym %s\n", line); - } else { -@@ -154,12 +141,14 @@ static kbd_layout_t *parse_keyboard_layo - return k; - } - --static void *init_keyboard_layout(const char *language) -+ -+void *init_keyboard_layout(const name2keysym_t *table, const char *language) - { -- return parse_keyboard_layout(language, 0); -+ return parse_keyboard_layout(table, language, 0); - } - --static int keysym2scancode(void *kbd_layout, int keysym) -+ -+int keysym2scancode(void *kbd_layout, int keysym) - { - kbd_layout_t *k = kbd_layout; - if (keysym < MAX_NORMAL_KEYCODE) { -@@ -180,7 +169,7 @@ static int keysym2scancode(void *kbd_lay - return 0; - } - --static inline int keycode_is_keypad(void *kbd_layout, int keycode) -+int keycode_is_keypad(void *kbd_layout, int keycode) - { - kbd_layout_t *k = kbd_layout; - struct key_range *kr; -@@ -191,7 +180,7 @@ static inline int keycode_is_keypad(void - return 0; - } - --static inline int keysym_is_numlock(void *kbd_layout, int keysym) -+int keysym_is_numlock(void *kbd_layout, int keysym) - { - kbd_layout_t *k = kbd_layout; - struct key_range *kr; -Index: qemu-kvm-0.10/qemu/keymaps.h -=================================================================== ---- /dev/null -+++ qemu-kvm-0.10/qemu/keymaps.h -@@ -0,0 +1,60 @@ -+/* -+ * QEMU keysym to keycode conversion using rdesktop keymaps -+ * -+ * Copyright (c) 2004 Johannes Schindelin -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a copy -+ * of this software and associated documentation files (the "Software"), to deal -+ * in the Software without restriction, including without limitation the rights -+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -+ * copies of the Software, and to permit persons to whom the Software is -+ * furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -+ * THE SOFTWARE. -+ */ -+ -+#ifndef __QEMU_KEYMAPS_H__ -+#define __QEMU_KEYMAPS_H__ -+ -+#include "qemu-common.h" -+ -+typedef struct { -+ const char* name; -+ int keysym; -+} name2keysym_t; -+ -+struct key_range { -+ int start; -+ int end; -+ struct key_range *next; -+}; -+ -+#define MAX_NORMAL_KEYCODE 512 -+#define MAX_EXTRA_COUNT 256 -+typedef struct { -+ uint16_t keysym2keycode[MAX_NORMAL_KEYCODE]; -+ struct { -+ int keysym; -+ uint16_t keycode; -+ } keysym2keycode_extra[MAX_EXTRA_COUNT]; -+ int extra_count; -+ struct key_range *keypad_range; -+ struct key_range *numlock_range; -+} kbd_layout_t; -+ -+ -+void *init_keyboard_layout(const name2keysym_t *table, const char *language); -+int keysym2scancode(void *kbd_layout, int keysym); -+int keycode_is_keypad(void *kbd_layout, int keycode); -+int keysym_is_numlock(void *kbd_layout, int keysym); -+ -+#endif /* __QEMU_KEYMAPS_H__ */ -Index: qemu-kvm-0.10/qemu/sdl.c -=================================================================== ---- qemu-kvm-0.10.orig/qemu/sdl.c -+++ qemu-kvm-0.10/qemu/sdl.c -@@ -109,7 +109,6 @@ static void sdl_resize(DisplayState *ds) - /* generic keyboard conversion */ - - #include "sdl_keysym.h" --#include "keymaps.c" - - static kbd_layout_t *kbd_layout = NULL; - -@@ -677,7 +676,7 @@ void sdl_display_init(DisplayState *ds, - keyboard_layout = "en-us"; - #endif - if(keyboard_layout) { -- kbd_layout = init_keyboard_layout(keyboard_layout); -+ kbd_layout = init_keyboard_layout(name2keysym, keyboard_layout); - if (!kbd_layout) - exit(1); - } -Index: qemu-kvm-0.10/qemu/sdl_keysym.h -=================================================================== ---- qemu-kvm-0.10.orig/qemu/sdl_keysym.h -+++ qemu-kvm-0.10/qemu/sdl_keysym.h -@@ -1,7 +1,6 @@ --typedef struct { -- const char* name; -- int keysym; --} name2keysym_t; -+ -+#include "keymaps.h" -+ - static const name2keysym_t name2keysym[]={ - /* ascii */ - { "space", 0x020}, -Index: qemu-kvm-0.10/qemu/vnc.c -=================================================================== ---- qemu-kvm-0.10.orig/qemu/vnc.c -+++ qemu-kvm-0.10/qemu/vnc.c -@@ -35,7 +35,6 @@ - - #include "vnc.h" - #include "vnc_keysym.h" --#include "keymaps.c" - #include "d3des.h" - - #ifdef CONFIG_VNC_TLS -@@ -2420,9 +2419,9 @@ void vnc_display_init(DisplayState *ds) - vs->ds = ds; - - if (keyboard_layout) -- vs->kbd_layout = init_keyboard_layout(keyboard_layout); -+ vs->kbd_layout = init_keyboard_layout(name2keysym, keyboard_layout); - else -- vs->kbd_layout = init_keyboard_layout("en-us"); -+ vs->kbd_layout = init_keyboard_layout(name2keysym, "en-us"); - - if (!vs->kbd_layout) - exit(1); -Index: qemu-kvm-0.10/qemu/vnc_keysym.h -=================================================================== ---- qemu-kvm-0.10.orig/qemu/vnc_keysym.h -+++ qemu-kvm-0.10/qemu/vnc_keysym.h -@@ -1,7 +1,6 @@ --typedef struct { -- const char* name; -- int keysym; --} name2keysym_t; -+ -+#include "keymaps.h" -+ - static const name2keysym_t name2keysym[]={ - /* ascii */ - { "space", 0x020}, diff --git a/04-vnc-struct.patch b/04-vnc-struct.patch deleted file mode 100644 index eb7a346..0000000 --- a/04-vnc-struct.patch +++ /dev/null @@ -1,304 +0,0 @@ -Index: qemu-kvm-0.10/qemu/vnc.c -=================================================================== ---- qemu-kvm-0.10.orig/qemu/vnc.c -+++ qemu-kvm-0.10/qemu/vnc.c -@@ -3,6 +3,7 @@ - * - * Copyright (C) 2006 Anthony Liguori - * Copyright (C) 2006 Fabrice Bellard -+ * Copyright (C) 2009 Red Hat, Inc - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal -@@ -23,25 +24,16 @@ - * THE SOFTWARE. - */ - --#include "qemu-common.h" --#include "console.h" -+#include "vnc.h" - #include "sysemu.h" - #include "qemu_socket.h" - #include "qemu-timer.h" --#include "audio/audio.h" --#include - - #define VNC_REFRESH_INTERVAL (1000 / 30) - --#include "vnc.h" - #include "vnc_keysym.h" - #include "d3des.h" - --#ifdef CONFIG_VNC_TLS --#include --#include --#endif /* CONFIG_VNC_TLS */ -- - // #define _VNC_DEBUG 1 - - #ifdef _VNC_DEBUG -@@ -64,103 +56,6 @@ static void vnc_debug_gnutls_log(int lev - } \ - } - --typedef struct Buffer --{ -- size_t capacity; -- size_t offset; -- uint8_t *buffer; --} Buffer; -- --typedef struct VncState VncState; -- --typedef int VncReadEvent(VncState *vs, uint8_t *data, size_t len); -- --typedef void VncWritePixels(VncState *vs, void *data, int size); -- --typedef void VncSendHextileTile(VncState *vs, -- int x, int y, int w, int h, -- void *last_bg, -- void *last_fg, -- int *has_bg, int *has_fg); -- --#define VNC_MAX_WIDTH 2048 --#define VNC_MAX_HEIGHT 2048 --#define VNC_DIRTY_WORDS (VNC_MAX_WIDTH / (16 * 32)) -- --#define VNC_AUTH_CHALLENGE_SIZE 16 -- --typedef struct VncDisplay VncDisplay; -- --struct VncDisplay --{ -- int lsock; -- DisplayState *ds; -- VncState *clients; -- kbd_layout_t *kbd_layout; -- -- char *display; -- char *password; -- int auth; --#ifdef CONFIG_VNC_TLS -- int subauth; -- int x509verify; -- -- char *x509cacert; -- char *x509cacrl; -- char *x509cert; -- char *x509key; --#endif --}; -- --struct VncState --{ -- QEMUTimer *timer; -- int csock; -- DisplayState *ds; -- VncDisplay *vd; -- int need_update; -- uint32_t dirty_row[VNC_MAX_HEIGHT][VNC_DIRTY_WORDS]; -- char *old_data; -- uint32_t features; -- int absolute; -- int last_x; -- int last_y; -- -- uint32_t vnc_encoding; -- uint8_t tight_quality; -- uint8_t tight_compression; -- -- int major; -- int minor; -- -- char challenge[VNC_AUTH_CHALLENGE_SIZE]; -- --#ifdef CONFIG_VNC_TLS -- int wiremode; -- gnutls_session_t tls_session; --#endif -- -- Buffer output; -- Buffer input; -- /* current output mode information */ -- VncWritePixels *write_pixels; -- VncSendHextileTile *send_hextile_tile; -- DisplaySurface clientds, serverds; -- -- CaptureVoiceOut *audio_cap; -- struct audsettings as; -- -- VncReadEvent *read_handler; -- size_t read_handler_expect; -- /* input */ -- uint8_t modifiers_state[256]; -- -- Buffer zlib; -- Buffer zlib_tmp; -- z_stream zlib_stream[4]; -- -- VncState *next; --}; - - static VncDisplay *vnc_display; /* needed for info vnc */ - static DisplayChangeListener *dcl; -Index: qemu-kvm-0.10/qemu/vnc.h -=================================================================== ---- qemu-kvm-0.10.orig/qemu/vnc.h -+++ qemu-kvm-0.10/qemu/vnc.h -@@ -1,5 +1,148 @@ --#ifndef __VNCTIGHT_H --#define __VNCTIGHT_H -+/* -+ * QEMU VNC display driver -+ * -+ * Copyright (C) 2006 Anthony Liguori -+ * Copyright (C) 2006 Fabrice Bellard -+ * Copyright (C) 2009 Red Hat, Inc -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a copy -+ * of this software and associated documentation files (the "Software"), to deal -+ * in the Software without restriction, including without limitation the rights -+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -+ * copies of the Software, and to permit persons to whom the Software is -+ * furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -+ * THE SOFTWARE. -+ */ -+ -+#ifndef __QEMU_VNC_H -+#define __QEMU_VNC_H -+ -+#include "qemu-common.h" -+#include "console.h" -+#include "audio/audio.h" -+#include -+ -+#ifdef CONFIG_VNC_TLS -+#include -+#include -+#endif /* CONFIG_VNC_TLS */ -+ -+#include "keymaps.h" -+ -+/***************************************************************************** -+ * -+ * Core data structures -+ * -+ *****************************************************************************/ -+ -+typedef struct Buffer -+{ -+ size_t capacity; -+ size_t offset; -+ uint8_t *buffer; -+} Buffer; -+ -+typedef struct VncState VncState; -+ -+typedef int VncReadEvent(VncState *vs, uint8_t *data, size_t len); -+ -+typedef void VncWritePixels(VncState *vs, void *data, int size); -+ -+typedef void VncSendHextileTile(VncState *vs, -+ int x, int y, int w, int h, -+ void *last_bg, -+ void *last_fg, -+ int *has_bg, int *has_fg); -+ -+#define VNC_MAX_WIDTH 2048 -+#define VNC_MAX_HEIGHT 2048 -+#define VNC_DIRTY_WORDS (VNC_MAX_WIDTH / (16 * 32)) -+ -+#define VNC_AUTH_CHALLENGE_SIZE 16 -+ -+typedef struct VncDisplay VncDisplay; -+ -+struct VncDisplay -+{ -+ int lsock; -+ DisplayState *ds; -+ VncState *clients; -+ kbd_layout_t *kbd_layout; -+ -+ char *display; -+ char *password; -+ int auth; -+#ifdef CONFIG_VNC_TLS -+ int subauth; -+ int x509verify; -+ -+ char *x509cacert; -+ char *x509cacrl; -+ char *x509cert; -+ char *x509key; -+#endif -+}; -+ -+struct VncState -+{ -+ QEMUTimer *timer; -+ int csock; -+ DisplayState *ds; -+ VncDisplay *vd; -+ int need_update; -+ uint32_t dirty_row[VNC_MAX_HEIGHT][VNC_DIRTY_WORDS]; -+ char *old_data; -+ uint32_t features; -+ int absolute; -+ int last_x; -+ int last_y; -+ -+ uint32_t vnc_encoding; -+ uint8_t tight_quality; -+ uint8_t tight_compression; -+ -+ int major; -+ int minor; -+ -+ char challenge[VNC_AUTH_CHALLENGE_SIZE]; -+ -+#ifdef CONFIG_VNC_TLS -+ int wiremode; -+ gnutls_session_t tls_session; -+#endif -+ -+ Buffer output; -+ Buffer input; -+ /* current output mode information */ -+ VncWritePixels *write_pixels; -+ VncSendHextileTile *send_hextile_tile; -+ DisplaySurface clientds, serverds; -+ -+ CaptureVoiceOut *audio_cap; -+ struct audsettings as; -+ -+ VncReadEvent *read_handler; -+ size_t read_handler_expect; -+ /* input */ -+ uint8_t modifiers_state[256]; -+ -+ Buffer zlib; -+ Buffer zlib_tmp; -+ z_stream zlib_stream[4]; -+ -+ VncState *next; -+}; -+ - - /***************************************************************************** - * -@@ -111,4 +254,4 @@ enum { - #define VNC_FEATURE_ZLIB_MASK (1 << VNC_FEATURE_ZLIB) - #define VNC_FEATURE_COPYRECT_MASK (1 << VNC_FEATURE_COPYRECT) - --#endif /* __VNCTIGHT_H */ -+#endif /* __QEMU_VNC_H */ diff --git a/05-vnc-tls-vencrypt.patch b/05-vnc-tls-vencrypt.patch deleted file mode 100644 index 625a5b6..0000000 --- a/05-vnc-tls-vencrypt.patch +++ /dev/null @@ -1,1644 +0,0 @@ -Index: qemu-kvm-0.10/qemu/Makefile -=================================================================== ---- qemu-kvm-0.10.orig/qemu/Makefile -+++ qemu-kvm-0.10/qemu/Makefile -@@ -149,6 +149,9 @@ ifdef CONFIG_CURSES - OBJS+=curses.o - endif - OBJS+=vnc.o d3des.o -+ifdef CONFIG_VNC_TLS -+OBJS+=vnc-tls.o vnc-auth-vencrypt.o -+endif - - ifdef CONFIG_COCOA - OBJS+=cocoa.o -@@ -172,10 +175,16 @@ sdl.o: sdl.c keymaps.h sdl_keysym.h - - sdl.o audio/sdlaudio.o: CFLAGS += $(SDL_CFLAGS) - --vnc.o: vnc.c keymaps.h sdl_keysym.h vnchextile.h d3des.c d3des.h -+vnc.h: vnc-tls.h vnc-auth-vencrypt.h keymaps.h -+ -+vnc.o: vnc.c vnc.h vnc_keysym.h vnchextile.h d3des.c d3des.h - - vnc.o: CFLAGS += $(CONFIG_VNC_TLS_CFLAGS) - -+vnc-tls.o: vnc-tls.c vnc.h -+ -+vnc-auth-vencrypt.o: vnc-auth-vencrypt.c vnc.h -+ - curses.o: curses.c keymaps.h curses_keys.h - - bt-host.o: CFLAGS += $(CONFIG_BLUEZ_CFLAGS) -Index: qemu-kvm-0.10/qemu/vnc-auth-vencrypt.c -=================================================================== ---- /dev/null -+++ qemu-kvm-0.10/qemu/vnc-auth-vencrypt.c -@@ -0,0 +1,167 @@ -+/* -+ * QEMU VNC display driver: VeNCrypt authentication setup -+ * -+ * Copyright (C) 2006 Anthony Liguori -+ * Copyright (C) 2006 Fabrice Bellard -+ * Copyright (C) 2009 Red Hat, Inc -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a copy -+ * of this software and associated documentation files (the "Software"), to deal -+ * in the Software without restriction, including without limitation the rights -+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -+ * copies of the Software, and to permit persons to whom the Software is -+ * furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -+ * THE SOFTWARE. -+ */ -+ -+#include "vnc.h" -+ -+ -+static void start_auth_vencrypt_subauth(VncState *vs) -+{ -+ switch (vs->vd->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 */ -+ start_client_init(vs); -+ break; -+ -+ case VNC_AUTH_VENCRYPT_TLSVNC: -+ case VNC_AUTH_VENCRYPT_X509VNC: -+ VNC_DEBUG("Start TLS auth VNC\n"); -+ start_auth_vnc(vs); -+ break; -+ -+ default: /* Should not be possible, but just in case */ -+ VNC_DEBUG("Reject auth %d\n", vs->vd->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); -+ } -+} -+ -+static void vnc_tls_handshake_io(void *opaque); -+ -+static int vnc_start_vencrypt_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_tls_handshake_io, NULL, vs); -+ else -+ qemu_set_fd_handler(vs->csock, NULL, vnc_tls_handshake_io, vs); -+ return 0; -+ } -+ VNC_DEBUG("Handshake failed %s\n", gnutls_strerror(ret)); -+ vnc_client_error(vs); -+ return -1; -+ } -+ -+ if (vs->vd->tls.x509verify) { -+ if (vnc_tls_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->tls.wiremode = VNC_WIREMODE_TLS; -+ qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, vnc_client_write, vs); -+ -+ start_auth_vencrypt_subauth(vs); -+ -+ return 0; -+} -+ -+static void vnc_tls_handshake_io(void *opaque) { -+ struct VncState *vs = (struct VncState *)opaque; -+ -+ VNC_DEBUG("Handshake IO continue\n"); -+ vnc_start_vencrypt_handshake(vs); -+} -+ -+ -+ -+#define NEED_X509_AUTH(vs) \ -+ ((vs)->vd->subauth == VNC_AUTH_VENCRYPT_X509NONE || \ -+ (vs)->vd->subauth == VNC_AUTH_VENCRYPT_X509VNC || \ -+ (vs)->vd->subauth == VNC_AUTH_VENCRYPT_X509PLAIN) -+ -+ -+static int protocol_client_vencrypt_auth(VncState *vs, uint8_t *data, size_t len) -+{ -+ int auth = read_u32(data, 0); -+ -+ if (auth != vs->vd->subauth) { -+ VNC_DEBUG("Rejecting auth %d\n", auth); -+ vnc_write_u8(vs, 0); /* Reject auth */ -+ vnc_flush(vs); -+ vnc_client_error(vs); -+ } else { -+ VNC_DEBUG("Accepting auth %d, setting up TLS for handshake\n", auth); -+ vnc_write_u8(vs, 1); /* Accept auth */ -+ vnc_flush(vs); -+ -+ if (vnc_tls_client_setup(vs, NEED_X509_AUTH(vs)) < 0) { -+ VNC_DEBUG("Failed to setup TLS\n"); -+ return 0; -+ } -+ -+ VNC_DEBUG("Start TLS VeNCrypt handshake process\n"); -+ if (vnc_start_vencrypt_handshake(vs) < 0) { -+ VNC_DEBUG("Failed to start TLS handshake\n"); -+ return 0; -+ } -+ } -+ return 0; -+} -+ -+static int protocol_client_vencrypt_init(VncState *vs, uint8_t *data, size_t len) -+{ -+ if (data[0] != 0 || -+ data[1] != 2) { -+ VNC_DEBUG("Unsupported VeNCrypt protocol %d.%d\n", (int)data[0], (int)data[1]); -+ vnc_write_u8(vs, 1); /* Reject version */ -+ vnc_flush(vs); -+ vnc_client_error(vs); -+ } else { -+ VNC_DEBUG("Sending allowed auth %d\n", vs->vd->subauth); -+ vnc_write_u8(vs, 0); /* Accept version */ -+ vnc_write_u8(vs, 1); /* Number of sub-auths */ -+ vnc_write_u32(vs, vs->vd->subauth); /* The supported auth */ -+ vnc_flush(vs); -+ vnc_read_when(vs, protocol_client_vencrypt_auth, 4); -+ } -+ return 0; -+} -+ -+ -+void start_auth_vencrypt(VncState *vs) -+{ -+ /* Send VeNCrypt version 0.2 */ -+ vnc_write_u8(vs, 0); -+ vnc_write_u8(vs, 2); -+ -+ vnc_read_when(vs, protocol_client_vencrypt_init, 2); -+} -+ -Index: qemu-kvm-0.10/qemu/vnc-auth-vencrypt.h -=================================================================== ---- /dev/null -+++ qemu-kvm-0.10/qemu/vnc-auth-vencrypt.h -@@ -0,0 +1,33 @@ -+/* -+ * QEMU VNC display driver -+ * -+ * Copyright (C) 2006 Anthony Liguori -+ * Copyright (C) 2006 Fabrice Bellard -+ * Copyright (C) 2009 Red Hat, Inc -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a copy -+ * of this software and associated documentation files (the "Software"), to deal -+ * in the Software without restriction, including without limitation the rights -+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -+ * copies of the Software, and to permit persons to whom the Software is -+ * furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -+ * THE SOFTWARE. -+ */ -+ -+ -+#ifndef __QEMU_VNC_AUTH_VENCRYPT_H__ -+#define __QEMU_VNC_AUTH_VENCRYPT_H__ -+ -+void start_auth_vencrypt(VncState *vs); -+ -+#endif /* __QEMU_VNC_AUTH_VENCRYPT_H__ */ -Index: qemu-kvm-0.10/qemu/vnc-tls.c -=================================================================== ---- /dev/null -+++ qemu-kvm-0.10/qemu/vnc-tls.c -@@ -0,0 +1,414 @@ -+/* -+ * QEMU VNC display driver: TLS helpers -+ * -+ * Copyright (C) 2006 Anthony Liguori -+ * Copyright (C) 2006 Fabrice Bellard -+ * Copyright (C) 2009 Red Hat, Inc -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a copy -+ * of this software and associated documentation files (the "Software"), to deal -+ * in the Software without restriction, including without limitation the rights -+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -+ * copies of the Software, and to permit persons to whom the Software is -+ * furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -+ * THE SOFTWARE. -+ */ -+ -+#include "vnc.h" -+#include "qemu_socket.h" -+ -+#if defined(_VNC_DEBUG) && _VNC_DEBUG >= 2 -+/* Very verbose, so only enabled for _VNC_DEBUG >= 2 */ -+static void vnc_debug_gnutls_log(int level, const char* str) { -+ VNC_DEBUG("%d %s", level, str); -+} -+#endif /* defined(_VNC_DEBUG) && _VNC_DEBUG >= 2 */ -+ -+ -+#define DH_BITS 1024 -+static 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 defined(_VNC_DEBUG) && _VNC_DEBUG >= 2 -+ gnutls_global_set_log_level(10); -+ gnutls_global_set_log_function(vnc_debug_gnutls_log); -+#endif -+ -+ tlsinitialized = 1; -+ -+ return 1; -+} -+ -+static ssize_t vnc_tls_push(gnutls_transport_ptr_t transport, -+ const void *data, -+ size_t len) { -+ struct VncState *vs = (struct VncState *)transport; -+ int ret; -+ -+ retry: -+ ret = send(vs->csock, data, len, 0); -+ if (ret < 0) { -+ if (errno == EINTR) -+ goto retry; -+ return -1; -+ } -+ return ret; -+} -+ -+ -+static ssize_t vnc_tls_pull(gnutls_transport_ptr_t transport, -+ void *data, -+ size_t len) { -+ struct VncState *vs = (struct VncState *)transport; -+ int ret; -+ -+ retry: -+ ret = recv(vs->csock, data, len, 0); -+ if (ret < 0) { -+ if (errno == EINTR) -+ goto retry; -+ return -1; -+ } -+ return ret; -+} -+ -+ -+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(VncDisplay *vd) -+{ -+ gnutls_certificate_credentials_t x509_cred; -+ int ret; -+ -+ if (!vd->tls.x509cacert) { -+ VNC_DEBUG("No CA x509 certificate specified\n"); -+ return NULL; -+ } -+ if (!vd->tls.x509cert) { -+ VNC_DEBUG("No server x509 certificate specified\n"); -+ return NULL; -+ } -+ if (!vd->tls.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, -+ vd->tls.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, -+ vd->tls.x509cert, -+ vd->tls.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 (vd->tls.x509cacrl) { -+ if ((ret = gnutls_certificate_set_x509_crl_file(x509_cred, -+ vd->tls.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; -+} -+ -+ -+int vnc_tls_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; -+} -+ -+ -+int vnc_tls_client_setup(struct VncState *vs, -+ int needX509Creds) { -+ 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, needX509Creds ? 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; -+ } -+ -+ if (needX509Creds) { -+ gnutls_certificate_server_credentials x509_cred = vnc_tls_initialize_x509_cred(vs->vd); -+ if (!x509_cred) { -+ gnutls_deinit(vs->tls.session); -+ vs->tls.session = NULL; -+ vnc_client_error(vs); -+ return -1; -+ } -+ if (gnutls_credentials_set(vs->tls.session, GNUTLS_CRD_CERTIFICATE, x509_cred) < 0) { -+ gnutls_deinit(vs->tls.session); -+ vs->tls.session = NULL; -+ gnutls_certificate_free_credentials(x509_cred); -+ vnc_client_error(vs); -+ return -1; -+ } -+ if (vs->vd->tls.x509verify) { -+ VNC_DEBUG("Requesting a client certificate\n"); -+ gnutls_certificate_server_set_request (vs->tls.session, GNUTLS_CERT_REQUEST); -+ } -+ -+ } else { -+ gnutls_anon_server_credentials anon_cred = vnc_tls_initialize_anon_cred(); -+ if (!anon_cred) { -+ gnutls_deinit(vs->tls.session); -+ vs->tls.session = NULL; -+ vnc_client_error(vs); -+ return -1; -+ } -+ if (gnutls_credentials_set(vs->tls.session, GNUTLS_CRD_ANON, anon_cred) < 0) { -+ gnutls_deinit(vs->tls.session); -+ vs->tls.session = NULL; -+ gnutls_anon_free_server_credentials(anon_cred); -+ vnc_client_error(vs); -+ return -1; -+ } -+ } -+ -+ gnutls_transport_set_ptr(vs->tls.session, (gnutls_transport_ptr_t)vs); -+ gnutls_transport_set_push_function(vs->tls.session, vnc_tls_push); -+ gnutls_transport_set_pull_function(vs->tls.session, vnc_tls_pull); -+ } -+ return 0; -+} -+ -+ -+void vnc_tls_client_cleanup(struct VncState *vs) -+{ -+ if (vs->tls.session) { -+ gnutls_deinit(vs->tls.session); -+ vs->tls.session = NULL; -+ } -+ vs->tls.wiremode = VNC_WIREMODE_CLEAR; -+} -+ -+ -+ -+static int vnc_set_x509_credential(VncDisplay *vd, -+ const char *certdir, -+ const char *filename, -+ char **cred, -+ int ignoreMissing) -+{ -+ struct stat sb; -+ -+ if (*cred) { -+ qemu_free(*cred); -+ *cred = NULL; -+ } -+ -+ *cred = qemu_malloc(strlen(certdir) + strlen(filename) + 2); -+ -+ strcpy(*cred, certdir); -+ strcat(*cred, "/"); -+ strcat(*cred, filename); -+ -+ VNC_DEBUG("Check %s\n", *cred); -+ if (stat(*cred, &sb) < 0) { -+ qemu_free(*cred); -+ *cred = NULL; -+ if (ignoreMissing && errno == ENOENT) -+ return 0; -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+#define X509_CA_CERT_FILE "ca-cert.pem" -+#define X509_CA_CRL_FILE "ca-crl.pem" -+#define X509_SERVER_KEY_FILE "server-key.pem" -+#define X509_SERVER_CERT_FILE "server-cert.pem" -+ -+ -+int vnc_tls_set_x509_creds_dir(VncDisplay *vd, -+ const char *certdir) -+{ -+ if (vnc_set_x509_credential(vd, certdir, X509_CA_CERT_FILE, &vd->tls.x509cacert, 0) < 0) -+ goto cleanup; -+ if (vnc_set_x509_credential(vd, certdir, X509_CA_CRL_FILE, &vd->tls.x509cacrl, 1) < 0) -+ goto cleanup; -+ if (vnc_set_x509_credential(vd, certdir, X509_SERVER_CERT_FILE, &vd->tls.x509cert, 0) < 0) -+ goto cleanup; -+ if (vnc_set_x509_credential(vd, certdir, X509_SERVER_KEY_FILE, &vd->tls.x509key, 0) < 0) -+ goto cleanup; -+ -+ return 0; -+ -+ cleanup: -+ qemu_free(vd->tls.x509cacert); -+ qemu_free(vd->tls.x509cacrl); -+ qemu_free(vd->tls.x509cert); -+ qemu_free(vd->tls.x509key); -+ vd->tls.x509cacert = vd->tls.x509cacrl = vd->tls.x509cert = vd->tls.x509key = NULL; -+ return -1; -+} -+ -Index: qemu-kvm-0.10/qemu/vnc-tls.h -=================================================================== ---- /dev/null -+++ qemu-kvm-0.10/qemu/vnc-tls.h -@@ -0,0 +1,70 @@ -+/* -+ * QEMU VNC display driver. TLS helpers -+ * -+ * Copyright (C) 2006 Anthony Liguori -+ * Copyright (C) 2006 Fabrice Bellard -+ * Copyright (C) 2009 Red Hat, Inc -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a copy -+ * of this software and associated documentation files (the "Software"), to deal -+ * in the Software without restriction, including without limitation the rights -+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -+ * copies of the Software, and to permit persons to whom the Software is -+ * furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -+ * THE SOFTWARE. -+ */ -+ -+ -+#ifndef __QEMU_VNC_TLS_H__ -+#define __QEMU_VNC_TLS_H__ -+ -+#include -+#include -+ -+enum { -+ VNC_WIREMODE_CLEAR, -+ VNC_WIREMODE_TLS, -+}; -+ -+typedef struct VncDisplayTLS VncDisplayTLS; -+typedef struct VncStateTLS VncStateTLS; -+ -+/* Server state */ -+struct VncDisplayTLS { -+ int x509verify; /* Non-zero if server requests & validates client cert */ -+ -+ /* Paths to x509 certs/keys */ -+ char *x509cacert; -+ char *x509cacrl; -+ char *x509cert; -+ char *x509key; -+}; -+ -+/* Per client state */ -+struct VncStateTLS { -+ /* Whether data is being TLS encrypted yet */ -+ int wiremode; -+ gnutls_session_t session; -+}; -+ -+int vnc_tls_client_setup(VncState *vs, int x509Creds); -+void vnc_tls_client_cleanup(VncState *vs); -+ -+int vnc_tls_validate_certificate(VncState *vs); -+ -+int vnc_tls_set_x509_creds_dir(VncDisplay *vd, -+ const char *path); -+ -+ -+#endif /* __QEMU_VNC_TLS_H__ */ -+ -Index: qemu-kvm-0.10/qemu/vnc.c -=================================================================== ---- qemu-kvm-0.10.orig/qemu/vnc.c -+++ qemu-kvm-0.10/qemu/vnc.c -@@ -34,21 +34,6 @@ - #include "vnc_keysym.h" - #include "d3des.h" - --// #define _VNC_DEBUG 1 -- --#ifdef _VNC_DEBUG --#define VNC_DEBUG(fmt, ...) do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0) -- --#if defined(CONFIG_VNC_TLS) && _VNC_DEBUG >= 2 --/* Very verbose, so only enabled for _VNC_DEBUG >= 2 */ --static void vnc_debug_gnutls_log(int level, const char* str) { -- VNC_DEBUG("%d %s", level, str); --} --#endif /* CONFIG_VNC_TLS && _VNC_DEBUG */ --#else --#define VNC_DEBUG(fmt, ...) do { } while (0) --#endif -- - #define count_bits(c, v) { \ - for (c = 0; v; v >>= 1) \ - { \ -@@ -204,14 +189,7 @@ static inline uint32_t vnc_has_feature(V - 3) resolutions > 1024 - */ - --static void vnc_write(VncState *vs, const void *data, size_t len); --static void vnc_write_u32(VncState *vs, uint32_t value); --static void vnc_write_s32(VncState *vs, int32_t value); --static void vnc_write_u16(VncState *vs, uint16_t value); --static void vnc_write_u8(VncState *vs, uint8_t value); --static void vnc_flush(VncState *vs); - static void vnc_update_client(void *opaque); --static void vnc_client_read(void *opaque); - - static void vnc_colordepth(VncState *vs); - -@@ -867,10 +845,7 @@ static int vnc_client_io_error(VncState - if (vs->input.buffer) qemu_free(vs->input.buffer); - if (vs->output.buffer) qemu_free(vs->output.buffer); - #ifdef CONFIG_VNC_TLS -- if (vs->tls_session) { -- gnutls_deinit(vs->tls_session); -- vs->tls_session = NULL; -- } -+ vnc_tls_client_cleanup(vs); - #endif /* CONFIG_VNC_TLS */ - audio_del(vs); - -@@ -896,19 +871,20 @@ static int vnc_client_io_error(VncState - return ret; - } - --static void vnc_client_error(VncState *vs) -+ -+void vnc_client_error(VncState *vs) - { - vnc_client_io_error(vs, -1, EINVAL); - } - --static void vnc_client_write(void *opaque) -+void vnc_client_write(void *opaque) - { - long ret; - VncState *vs = opaque; - - #ifdef CONFIG_VNC_TLS -- if (vs->tls_session) { -- ret = gnutls_write(vs->tls_session, vs->output.buffer, vs->output.offset); -+ if (vs->tls.session) { -+ ret = gnutls_write(vs->tls.session, vs->output.buffer, vs->output.offset); - if (ret < 0) { - if (ret == GNUTLS_E_AGAIN) - errno = EAGAIN; -@@ -931,13 +907,13 @@ static void vnc_client_write(void *opaqu - } - } - --static void vnc_read_when(VncState *vs, VncReadEvent *func, size_t expecting) -+void vnc_read_when(VncState *vs, VncReadEvent *func, size_t expecting) - { - vs->read_handler = func; - vs->read_handler_expect = expecting; - } - --static void vnc_client_read(void *opaque) -+void vnc_client_read(void *opaque) - { - VncState *vs = opaque; - long ret; -@@ -945,8 +921,8 @@ static void vnc_client_read(void *opaque - buffer_reserve(&vs->input, 4096); - - #ifdef CONFIG_VNC_TLS -- if (vs->tls_session) { -- ret = gnutls_read(vs->tls_session, buffer_end(&vs->input), 4096); -+ if (vs->tls.session) { -+ ret = gnutls_read(vs->tls.session, buffer_end(&vs->input), 4096); - if (ret < 0) { - if (ret == GNUTLS_E_AGAIN) - errno = EAGAIN; -@@ -980,7 +956,7 @@ static void vnc_client_read(void *opaque - } - } - --static void vnc_write(VncState *vs, const void *data, size_t len) -+void vnc_write(VncState *vs, const void *data, size_t len) - { - buffer_reserve(&vs->output, len); - -@@ -991,12 +967,12 @@ static void vnc_write(VncState *vs, cons - buffer_append(&vs->output, data, len); - } - --static void vnc_write_s32(VncState *vs, int32_t value) -+void vnc_write_s32(VncState *vs, int32_t value) - { - vnc_write_u32(vs, *(uint32_t *)&value); - } - --static void vnc_write_u32(VncState *vs, uint32_t value) -+void vnc_write_u32(VncState *vs, uint32_t value) - { - uint8_t buf[4]; - -@@ -1008,7 +984,7 @@ static void vnc_write_u32(VncState *vs, - vnc_write(vs, buf, 4); - } - --static void vnc_write_u16(VncState *vs, uint16_t value) -+void vnc_write_u16(VncState *vs, uint16_t value) - { - uint8_t buf[2]; - -@@ -1018,74 +994,39 @@ static void vnc_write_u16(VncState *vs, - vnc_write(vs, buf, 2); - } - --static void vnc_write_u8(VncState *vs, uint8_t value) -+void vnc_write_u8(VncState *vs, uint8_t value) - { - vnc_write(vs, (char *)&value, 1); - } - --static void vnc_flush(VncState *vs) -+void vnc_flush(VncState *vs) - { - if (vs->output.offset) - vnc_client_write(vs); - } - --static uint8_t read_u8(uint8_t *data, size_t offset) -+uint8_t read_u8(uint8_t *data, size_t offset) - { - return data[offset]; - } - --static uint16_t read_u16(uint8_t *data, size_t offset) -+uint16_t read_u16(uint8_t *data, size_t offset) - { - return ((data[offset] & 0xFF) << 8) | (data[offset + 1] & 0xFF); - } - --static int32_t read_s32(uint8_t *data, size_t offset) -+int32_t read_s32(uint8_t *data, size_t offset) - { - return (int32_t)((data[offset] << 24) | (data[offset + 1] << 16) | - (data[offset + 2] << 8) | data[offset + 3]); - } - --static uint32_t read_u32(uint8_t *data, size_t offset) -+uint32_t read_u32(uint8_t *data, size_t offset) - { - return ((data[offset] << 24) | (data[offset + 1] << 16) | - (data[offset + 2] << 8) | data[offset + 3]); - } - --#ifdef CONFIG_VNC_TLS --static ssize_t vnc_tls_push(gnutls_transport_ptr_t transport, -- const void *data, -- size_t len) { -- struct VncState *vs = (struct VncState *)transport; -- int ret; -- -- retry: -- ret = send(vs->csock, data, len, 0); -- if (ret < 0) { -- if (errno == EINTR) -- goto retry; -- return -1; -- } -- return ret; --} -- -- --static ssize_t vnc_tls_pull(gnutls_transport_ptr_t transport, -- void *data, -- size_t len) { -- struct VncState *vs = (struct VncState *)transport; -- int ret; -- -- retry: -- ret = recv(vs->csock, data, len, 0); -- if (ret < 0) { -- if (errno == EINTR) -- goto retry; -- return -1; -- } -- return ret; --} --#endif /* CONFIG_VNC_TLS */ -- - static void client_cut_text(VncState *vs, size_t len, uint8_t *text) - { - } -@@ -1668,6 +1609,11 @@ static int protocol_client_init(VncState - return 0; - } - -+void start_client_init(VncState *vs) -+{ -+ vnc_read_when(vs, protocol_client_init, 1); -+} -+ - static void make_challenge(VncState *vs) - { - int i; -@@ -1723,12 +1669,12 @@ static int protocol_client_auth_vnc(VncS - vnc_write_u32(vs, 0); /* Accept auth */ - vnc_flush(vs); - -- vnc_read_when(vs, protocol_client_init, 1); -+ start_client_init(vs); - } - return 0; - } - --static int start_auth_vnc(VncState *vs) -+void start_auth_vnc(VncState *vs) - { - make_challenge(vs); - /* Send client a 'random' challenge */ -@@ -1736,411 +1682,9 @@ static int start_auth_vnc(VncState *vs) - vnc_flush(vs); - - vnc_read_when(vs, protocol_client_auth_vnc, sizeof(vs->challenge)); -- return 0; --} -- -- --#ifdef CONFIG_VNC_TLS --#define DH_BITS 1024 --static 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 defined(_VNC_DEBUG) && _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->vd->x509cacert) { -- VNC_DEBUG("No CA x509 certificate specified\n"); -- return NULL; -- } -- if (!vs->vd->x509cert) { -- VNC_DEBUG("No server x509 certificate specified\n"); -- return NULL; -- } -- if (!vs->vd->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->vd->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->vd->x509cert, -- vs->vd->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->vd->x509cacrl) { -- if ((ret = gnutls_certificate_set_x509_crl_file(x509_cred, -- vs->vd->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->vd->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->vd->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->vd->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)->vd->subauth == VNC_AUTH_VENCRYPT_X509NONE || \ -- (vs)->vd->subauth == VNC_AUTH_VENCRYPT_X509VNC || \ -- (vs)->vd->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; -- } -- -- if (NEED_X509_AUTH(vs)) { -- gnutls_certificate_server_credentials x509_cred = vnc_tls_initialize_x509_cred(vs); -- if (!x509_cred) { -- gnutls_deinit(vs->tls_session); -- vs->tls_session = NULL; -- vnc_client_error(vs); -- return -1; -- } -- if (gnutls_credentials_set(vs->tls_session, GNUTLS_CRD_CERTIFICATE, x509_cred) < 0) { -- gnutls_deinit(vs->tls_session); -- vs->tls_session = NULL; -- gnutls_certificate_free_credentials(x509_cred); -- vnc_client_error(vs); -- return -1; -- } -- if (vs->vd->x509verify) { -- VNC_DEBUG("Requesting a client certificate\n"); -- gnutls_certificate_server_set_request (vs->tls_session, GNUTLS_CERT_REQUEST); -- } -- -- } else { -- gnutls_anon_server_credentials anon_cred = vnc_tls_initialize_anon_cred(); -- if (!anon_cred) { -- gnutls_deinit(vs->tls_session); -- vs->tls_session = NULL; -- vnc_client_error(vs); -- return -1; -- } -- if (gnutls_credentials_set(vs->tls_session, GNUTLS_CRD_ANON, anon_cred) < 0) { -- gnutls_deinit(vs->tls_session); -- vs->tls_session = NULL; -- gnutls_anon_free_server_credentials(anon_cred); -- vnc_client_error(vs); -- return -1; -- } -- } -- -- gnutls_transport_set_ptr(vs->tls_session, (gnutls_transport_ptr_t)vs); -- gnutls_transport_set_push_function(vs->tls_session, vnc_tls_push); -- gnutls_transport_set_pull_function(vs->tls_session, vnc_tls_pull); -- } -- -- VNC_DEBUG("Start TLS handshake process\n"); -- return vnc_continue_handshake(vs); --} -- --static int protocol_client_vencrypt_auth(VncState *vs, uint8_t *data, size_t len) --{ -- int auth = read_u32(data, 0); -- -- if (auth != vs->vd->subauth) { -- VNC_DEBUG("Rejecting auth %d\n", auth); -- vnc_write_u8(vs, 0); /* Reject auth */ -- vnc_flush(vs); -- vnc_client_error(vs); -- } else { -- VNC_DEBUG("Accepting auth %d, starting handshake\n", auth); -- vnc_write_u8(vs, 1); /* Accept auth */ -- vnc_flush(vs); -- -- if (vnc_start_tls(vs) < 0) { -- VNC_DEBUG("Failed to complete TLS\n"); -- return 0; -- } -- } -- return 0; --} -- --static int protocol_client_vencrypt_init(VncState *vs, uint8_t *data, size_t len) --{ -- if (data[0] != 0 || -- data[1] != 2) { -- VNC_DEBUG("Unsupported VeNCrypt protocol %d.%d\n", (int)data[0], (int)data[1]); -- vnc_write_u8(vs, 1); /* Reject version */ -- vnc_flush(vs); -- vnc_client_error(vs); -- } else { -- VNC_DEBUG("Sending allowed auth %d\n", vs->vd->subauth); -- vnc_write_u8(vs, 0); /* Accept version */ -- vnc_write_u8(vs, 1); /* Number of sub-auths */ -- vnc_write_u32(vs, vs->vd->subauth); /* The supported auth */ -- vnc_flush(vs); -- vnc_read_when(vs, protocol_client_vencrypt_auth, 4); -- } -- return 0; --} -- --static int start_auth_vencrypt(VncState *vs) --{ -- /* Send VeNCrypt version 0.2 */ -- vnc_write_u8(vs, 0); -- vnc_write_u8(vs, 2); -- -- vnc_read_when(vs, protocol_client_vencrypt_init, 2); -- return 0; --} --#endif /* CONFIG_VNC_TLS */ -- - static int protocol_client_auth(VncState *vs, uint8_t *data, size_t len) - { - /* We only advertise 1 auth scheme at a time, so client -@@ -2163,17 +1707,19 @@ static int protocol_client_auth(VncState - vnc_write_u32(vs, 0); /* Accept auth completion */ - vnc_flush(vs); - } -- vnc_read_when(vs, protocol_client_init, 1); -+ start_client_init(vs); - break; - - case VNC_AUTH_VNC: - VNC_DEBUG("Start VNC auth\n"); -- return start_auth_vnc(vs); -+ start_auth_vnc(vs); -+ break; - - #ifdef CONFIG_VNC_TLS - case VNC_AUTH_VENCRYPT: - VNC_DEBUG("Accept VeNCrypt auth\n");; -- return start_auth_vencrypt(vs); -+ start_auth_vencrypt(vs); -+ break; - #endif /* CONFIG_VNC_TLS */ - - default: /* Should not be possible, but just in case */ -@@ -2226,7 +1772,7 @@ static int protocol_version(VncState *vs - VNC_DEBUG("Tell client auth none\n"); - vnc_write_u32(vs, vs->vd->auth); - vnc_flush(vs); -- vnc_read_when(vs, protocol_client_init, 1); -+ start_client_init(vs); - } else if (vs->vd->auth == VNC_AUTH_VNC) { - VNC_DEBUG("Tell client VNC auth\n"); - vnc_write_u32(vs, vs->vd->auth); -@@ -2328,61 +1874,6 @@ void vnc_display_init(DisplayState *ds) - register_displaychangelistener(ds, dcl); - } - --#ifdef CONFIG_VNC_TLS --static int vnc_set_x509_credential(VncDisplay *vs, -- const char *certdir, -- const char *filename, -- char **cred, -- int ignoreMissing) --{ -- struct stat sb; -- -- if (*cred) { -- qemu_free(*cred); -- *cred = NULL; -- } -- -- *cred = qemu_malloc(strlen(certdir) + strlen(filename) + 2); -- -- strcpy(*cred, certdir); -- strcat(*cred, "/"); -- strcat(*cred, filename); -- -- VNC_DEBUG("Check %s\n", *cred); -- if (stat(*cred, &sb) < 0) { -- qemu_free(*cred); -- *cred = NULL; -- if (ignoreMissing && errno == ENOENT) -- return 0; -- return -1; -- } -- -- return 0; --} -- --static int vnc_set_x509_credential_dir(VncDisplay *vs, -- const char *certdir) --{ -- if (vnc_set_x509_credential(vs, certdir, X509_CA_CERT_FILE, &vs->x509cacert, 0) < 0) -- goto cleanup; -- if (vnc_set_x509_credential(vs, certdir, X509_CA_CRL_FILE, &vs->x509cacrl, 1) < 0) -- goto cleanup; -- if (vnc_set_x509_credential(vs, certdir, X509_SERVER_CERT_FILE, &vs->x509cert, 0) < 0) -- goto cleanup; -- if (vnc_set_x509_credential(vs, certdir, X509_SERVER_KEY_FILE, &vs->x509key, 0) < 0) -- goto cleanup; -- -- return 0; -- -- cleanup: -- qemu_free(vs->x509cacert); -- qemu_free(vs->x509cacrl); -- qemu_free(vs->x509cert); -- qemu_free(vs->x509key); -- vs->x509cacert = vs->x509cacrl = vs->x509cert = vs->x509key = NULL; -- return -1; --} --#endif /* CONFIG_VNC_TLS */ - - void vnc_display_close(DisplayState *ds) - { -@@ -2402,7 +1893,7 @@ void vnc_display_close(DisplayState *ds) - vs->auth = VNC_AUTH_INVALID; - #ifdef CONFIG_VNC_TLS - vs->subauth = VNC_AUTH_INVALID; -- vs->x509verify = 0; -+ vs->tls.x509verify = 0; - #endif - } - -@@ -2458,7 +1949,7 @@ int vnc_display_open(DisplayState *ds, c - char *start, *end; - x509 = 1; /* Require x509 certificates */ - if (strncmp(options, "x509verify", 10) == 0) -- vs->x509verify = 1; /* ...and verify client certs */ -+ vs->tls.x509verify = 1; /* ...and verify client certs */ - - /* Now check for 'x509=/some/path' postfix - * and use that to setup x509 certificate/key paths */ -@@ -2469,7 +1960,7 @@ int vnc_display_open(DisplayState *ds, c - char *path = qemu_strndup(start + 1, len); - - VNC_DEBUG("Trying certificate path '%s'\n", path); -- if (vnc_set_x509_credential_dir(vs, path) < 0) { -+ if (vnc_tls_set_x509_creds_dir(vs, path) < 0) { - fprintf(stderr, "Failed to find x509 certificates/keys in %s\n", path); - qemu_free(path); - qemu_free(vs->display); -Index: qemu-kvm-0.10/qemu/vnc.h -=================================================================== ---- qemu-kvm-0.10.orig/qemu/vnc.h -+++ qemu-kvm-0.10/qemu/vnc.h -@@ -32,13 +32,16 @@ - #include "audio/audio.h" - #include - --#ifdef CONFIG_VNC_TLS --#include --#include --#endif /* CONFIG_VNC_TLS */ -- - #include "keymaps.h" - -+// #define _VNC_DEBUG 1 -+ -+#ifdef _VNC_DEBUG -+#define VNC_DEBUG(fmt, ...) do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0) -+#else -+#define VNC_DEBUG(fmt, ...) do { } while (0) -+#endif -+ - /***************************************************************************** - * - * Core data structures -@@ -72,6 +75,11 @@ typedef void VncSendHextileTile(VncState - - typedef struct VncDisplay VncDisplay; - -+#ifdef CONFIG_VNC_TLS -+#include "vnc-tls.h" -+#include "vnc-auth-vencrypt.h" -+#endif -+ - struct VncDisplay - { - int lsock; -@@ -83,13 +91,8 @@ struct VncDisplay - char *password; - int auth; - #ifdef CONFIG_VNC_TLS -- int subauth; -- int x509verify; -- -- char *x509cacert; -- char *x509cacrl; -- char *x509cert; -- char *x509key; -+ int subauth; /* Used by VeNCrypt */ -+ VncDisplayTLS tls; - #endif - }; - -@@ -117,8 +120,7 @@ struct VncState - char challenge[VNC_AUTH_CHALLENGE_SIZE]; - - #ifdef CONFIG_VNC_TLS -- int wiremode; -- gnutls_session_t tls_session; -+ VncStateTLS tls; - #endif - - Buffer output; -@@ -162,12 +164,6 @@ enum { - VNC_AUTH_VENCRYPT = 19 - }; - --#ifdef CONFIG_VNC_TLS --enum { -- VNC_WIREMODE_CLEAR, -- VNC_WIREMODE_TLS, --}; -- - enum { - VNC_AUTH_VENCRYPT_PLAIN = 256, - VNC_AUTH_VENCRYPT_TLSNONE = 257, -@@ -178,12 +174,6 @@ enum { - VNC_AUTH_VENCRYPT_X509PLAIN = 262, - }; - --#define X509_CA_CERT_FILE "ca-cert.pem" --#define X509_CA_CRL_FILE "ca-crl.pem" --#define X509_SERVER_KEY_FILE "server-key.pem" --#define X509_SERVER_CERT_FILE "server-cert.pem" -- --#endif /* CONFIG_VNC_TLS */ - - /***************************************************************************** - * -@@ -254,4 +244,38 @@ enum { - #define VNC_FEATURE_ZLIB_MASK (1 << VNC_FEATURE_ZLIB) - #define VNC_FEATURE_COPYRECT_MASK (1 << VNC_FEATURE_COPYRECT) - -+ -+/***************************************************************************** -+ * -+ * Internal APIs -+ * -+ *****************************************************************************/ -+ -+/* Event loop functions */ -+void vnc_client_read(void *opaque); -+void vnc_client_write(void *opaque); -+ -+ -+/* Protocol I/O functions */ -+void vnc_write(VncState *vs, const void *data, size_t len); -+void vnc_write_u32(VncState *vs, uint32_t value); -+void vnc_write_s32(VncState *vs, int32_t value); -+void vnc_write_u16(VncState *vs, uint16_t value); -+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); -+ -+ -+/* Buffer I/O functions */ -+uint8_t read_u8(uint8_t *data, size_t offset); -+uint16_t read_u16(uint8_t *data, size_t offset); -+int32_t read_s32(uint8_t *data, size_t offset); -+uint32_t read_u32(uint8_t *data, size_t offset); -+ -+/* Protocol stage functions */ -+void vnc_client_error(VncState *vs); -+ -+void start_client_init(VncState *vs); -+void start_auth_vnc(VncState *vs); -+ - #endif /* __QEMU_VNC_H */ diff --git a/06-vnc-sasl.patch b/06-vnc-sasl.patch deleted file mode 100644 index f7eafd0..0000000 --- a/06-vnc-sasl.patch +++ /dev/null @@ -1,1526 +0,0 @@ -Index: qemu-kvm-0.10/qemu/Makefile -=================================================================== ---- qemu-kvm-0.10.orig/qemu/Makefile -+++ qemu-kvm-0.10/qemu/Makefile -@@ -152,6 +152,9 @@ OBJS+=vnc.o d3des.o - ifdef CONFIG_VNC_TLS - OBJS+=vnc-tls.o vnc-auth-vencrypt.o - endif -+ifdef CONFIG_VNC_SASL -+OBJS+=vnc-auth-sasl.o -+endif - - ifdef CONFIG_COCOA - OBJS+=cocoa.o -@@ -175,7 +178,7 @@ sdl.o: sdl.c keymaps.h sdl_keysym.h - - sdl.o audio/sdlaudio.o: CFLAGS += $(SDL_CFLAGS) - --vnc.h: vnc-tls.h vnc-auth-vencrypt.h keymaps.h -+vnc.h: vnc-tls.h vnc-auth-vencrypt.h vnc-auth-sasl.h keymaps.h - - vnc.o: vnc.c vnc.h vnc_keysym.h vnchextile.h d3des.c d3des.h - -@@ -185,6 +188,8 @@ vnc-tls.o: vnc-tls.c vnc.h - - vnc-auth-vencrypt.o: vnc-auth-vencrypt.c vnc.h - -+vnc-auth-sasl.o: vnc-auth-sasl.c vnc.h -+ - curses.o: curses.c keymaps.h curses_keys.h - - bt-host.o: CFLAGS += $(CONFIG_BLUEZ_CFLAGS) -Index: qemu-kvm-0.10/qemu/Makefile.target -=================================================================== ---- qemu-kvm-0.10.orig/qemu/Makefile.target -+++ qemu-kvm-0.10/qemu/Makefile.target -@@ -613,6 +613,11 @@ CPPFLAGS += $(CONFIG_VNC_TLS_CFLAGS) - LIBS += $(CONFIG_VNC_TLS_LIBS) - endif - -+ifdef CONFIG_VNC_SASL -+CPPFLAGS += $(CONFIG_VNC_SASL_CFLAGS) -+LIBS += $(CONFIG_VNC_SASL_LIBS) -+endif -+ - ifdef CONFIG_BLUEZ - LIBS += $(CONFIG_BLUEZ_LIBS) - endif -Index: qemu-kvm-0.10/qemu/configure -=================================================================== ---- qemu-kvm-0.10.orig/qemu/configure -+++ qemu-kvm-0.10/qemu/configure -@@ -164,6 +164,7 @@ fmod_lib="" - fmod_inc="" - oss_lib="" - vnc_tls="yes" -+vnc_sasl="yes" - bsd="no" - linux="no" - solaris="no" -@@ -404,6 +405,8 @@ for opt do - ;; - --disable-vnc-tls) vnc_tls="no" - ;; -+ --disable-vnc-sasl) vnc_sasl="no" -+ ;; - --disable-slirp) slirp="no" - ;; - --disable-vde) vde="no" -@@ -563,6 +566,7 @@ echo " Availab - echo " --enable-mixemu enable mixer emulation" - echo " --disable-brlapi disable BrlAPI" - echo " --disable-vnc-tls disable TLS encryption for VNC server" -+echo " --disable-vnc-sasl disable SASL encryption for VNC server" - echo " --disable-curses disable curses output" - echo " --disable-bluez disable bluez stack connectivity" - echo " --disable-kvm disable KVM acceleration support" -@@ -890,6 +894,25 @@ EOF - fi - - ########################################## -+# VNC SASL detection -+if test "$vnc_sasl" = "yes" ; then -+cat > $TMPC < -+#include -+int main(void) { sasl_server_init(NULL, "qemu"); return 0; } -+EOF -+ # Assuming Cyrus-SASL installed in /usr prefix -+ vnc_sasl_cflags="" -+ vnc_sasl_libs="-lsasl2" -+ if $cc $ARCH_CFLAGS -o $TMPE ${OS_CFLAGS} $vnc_sasl_cflags $TMPC \ -+ $vnc_sasl_libs 2> /dev/null ; then -+ : -+ else -+ vnc_sasl="no" -+ fi -+fi -+ -+########################################## - # vde libraries probe - if test "$vde" = "yes" ; then - cat > $TMPC << EOF -@@ -1224,6 +1247,11 @@ if test "$vnc_tls" = "yes" ; then - echo " TLS CFLAGS $vnc_tls_cflags" - echo " TLS LIBS $vnc_tls_libs" - fi -+echo "VNC SASL support $vnc_sasl" -+if test "$vnc_sasl" = "yes" ; then -+ echo " SASL CFLAGS $vnc_sasl_cflags" -+ echo " SASL LIBS $vnc_sasl_libs" -+fi - if test -n "$sparc_cpu"; then - echo "Target Sparc Arch $sparc_cpu" - fi -@@ -1467,6 +1495,12 @@ if test "$vnc_tls" = "yes" ; then - echo "CONFIG_VNC_TLS_LIBS=$vnc_tls_libs" >> $config_mak - echo "#define CONFIG_VNC_TLS 1" >> $config_h - fi -+if test "$vnc_sasl" = "yes" ; then -+ echo "CONFIG_VNC_SASL=yes" >> $config_mak -+ echo "CONFIG_VNC_SASL_CFLAGS=$vnc_sasl_cflags" >> $config_mak -+ echo "CONFIG_VNC_SASL_LIBS=$vnc_sasl_libs" >> $config_mak -+ echo "#define CONFIG_VNC_SASL 1" >> $config_h -+fi - qemu_version=`head $source_path/VERSION` - echo "VERSION=$qemu_version" >>$config_mak - echo "#define QEMU_VERSION \"$qemu_version\"" >> $config_h -Index: qemu-kvm-0.10/qemu/qemu-doc.texi -=================================================================== ---- qemu-kvm-0.10.orig/qemu/qemu-doc.texi -+++ qemu-kvm-0.10/qemu/qemu-doc.texi -@@ -624,6 +624,21 @@ path following this option specifies whe - be loaded from. See the @ref{vnc_security} section for details on generating - certificates. - -+@item sasl -+ -+Require that the client use SASL to authenticate with the VNC server. -+The exact choice of authentication method used is controlled from the -+system / user's SASL configuration file for the 'qemu' service. This -+is typically found in /etc/sasl2/qemu.conf. If running QEMU as an -+unprivileged user, an environment variable SASL_CONF_PATH can be used -+to make it search alternate locations for the service config. -+While some SASL auth methods can also provide data encryption (eg GSSAPI), -+it is recommended that SASL always be combined with the 'tls' and -+'x509' settings to enable use of SSL and server certificates. This -+ensures a data encryption preventing compromise of authentication -+credentials. See the @ref{vnc_security} section for details on using -+SASL authentication. -+ - @end table - - @end table -@@ -2069,7 +2084,10 @@ considerations depending on the deployme - * vnc_sec_certificate:: - * vnc_sec_certificate_verify:: - * vnc_sec_certificate_pw:: -+* vnc_sec_sasl:: -+* vnc_sec_certificate_sasl:: - * vnc_generate_cert:: -+* vnc_setup_sasl:: - @end menu - @node vnc_sec_none - @subsection Without passwords -@@ -2152,6 +2170,41 @@ Password: ******** - (qemu) - @end example - -+ -+@node vnc_sec_sasl -+@subsection With SASL authentication -+ -+The SASL authentication method is a VNC extension, that provides an -+easily extendable, pluggable authentication method. This allows for -+integration with a wide range of authentication mechanisms, such as -+PAM, GSSAPI/Kerberos, LDAP, SQL databases, one-time keys and more. -+The strength of the authentication depends on the exact mechanism -+configured. If the chosen mechanism also provides a SSF layer, then -+it will encrypt the datastream as well. -+ -+Refer to the later docs on how to choose the exact SASL mechanism -+used for authentication, but assuming use of one supporting SSF, -+then QEMU can be launched with: -+ -+@example -+qemu [...OPTIONS...] -vnc :1,sasl -monitor stdio -+@end example -+ -+@node vnc_sec_certificate_sasl -+@subsection With x509 certificates and SASL authentication -+ -+If the desired SASL authentication mechanism does not supported -+SSF layers, then it is strongly advised to run it in combination -+with TLS and x509 certificates. This provides securely encrypted -+data stream, avoiding risk of compromising of the security -+credentials. This can be enabled, by combining the 'sasl' option -+with the aforementioned TLS + x509 options: -+ -+@example -+qemu [...OPTIONS...] -vnc :1,tls,x509,sasl -monitor stdio -+@end example -+ -+ - @node vnc_generate_cert - @subsection Generating certificates for VNC - -@@ -2263,6 +2316,50 @@ EOF - The @code{client-key.pem} and @code{client-cert.pem} files should now be securely - copied to the client for which they were generated. - -+ -+@node vnc_setup_sasl -+ -+@subsection Configuring SASL mechanisms -+ -+The following documentation assumes use of the Cyrus SASL implementation on a -+Linux host, but the principals should apply to any other SASL impl. When SASL -+is enabled, the mechanism configuration will be loaded from system default -+SASL service config /etc/sasl2/qemu.conf. If running QEMU as an -+unprivileged user, an environment variable SASL_CONF_PATH can be used -+to make it search alternate locations for the service config. -+ -+The default configuration might contain -+ -+@example -+mech_list: digest-md5 -+sasldb_path: /etc/qemu/passwd.db -+@end example -+ -+This says to use the 'Digest MD5' mechanism, which is similar to the HTTP -+Digest-MD5 mechanism. The list of valid usernames & passwords is maintained -+in the /etc/qemu/passwd.db file, and can be updated using the saslpasswd2 -+command. While this mechanism is easy to configure and use, it is not -+considered secure by modern standards, so only suitable for developers / -+ad-hoc testing. -+ -+A more serious deployment might use Kerberos, which is done with the 'gssapi' -+mechanism -+ -+@example -+mech_list: gssapi -+keytab: /etc/qemu/krb5.tab -+@end example -+ -+For this to work the administrator of your KDC must generate a Kerberos -+principal for the server, with a name of 'qemu/somehost.example.com@@EXAMPLE.COM' -+replacing 'somehost.example.com' with the fully qualified host name of the -+machine running QEMU, and 'EXAMPLE.COM' with the Keberos Realm. -+ -+Other configurations will be left as an exercise for the reader. It should -+be noted that only Digest-MD5 and GSSAPI provides a SSF layer for data -+encryption. For all other mechanisms, VNC should always be configured to -+use TLS and x509 certificates to protect security credentials from snooping. -+ - @node gdb_usage - @section GDB usage - -Index: qemu-kvm-0.10/qemu/qemu.sasl -=================================================================== ---- /dev/null -+++ qemu-kvm-0.10/qemu/qemu.sasl -@@ -0,0 +1,34 @@ -+# If you want to use the non-TLS socket, then you *must* include -+# the GSSAPI or DIGEST-MD5 mechanisms, because they are the only -+# ones that can offer session encryption as well as authentication. -+# -+# If you're only using TLS, then you can turn on any mechanisms -+# you like for authentication, because TLS provides the encryption -+# -+# Default to a simple username+password mechanism -+# NB digest-md5 is no longer considered secure by current standards -+mech_list: digest-md5 -+ -+# Before you can use GSSAPI, you need a service principle on the -+# KDC server for libvirt, and that to be exported to the keytab -+# file listed below -+#mech_list: gssapi -+# -+# You can also list many mechanisms at once, then the user can choose -+# by adding '?auth=sasl.gssapi' to their libvirt URI, eg -+# qemu+tcp://hostname/system?auth=sasl.gssapi -+#mech_list: digest-md5 gssapi -+ -+# Some older builds of MIT kerberos on Linux ignore this option & -+# instead need KRB5_KTNAME env var. -+# For modern Linux, and other OS, this should be sufficient -+keytab: /etc/qemu/krb5.tab -+ -+# If using digest-md5 for username/passwds, then this is the file -+# containing the passwds. Use 'saslpasswd2 -a qemu [username]' -+# to add entries, and 'sasldblistusers2 -a qemu' to browse it -+sasldb_path: /etc/qemu/passwd.db -+ -+ -+auxprop_plugin: sasldb -+ -Index: qemu-kvm-0.10/qemu/vnc-auth-sasl.c -=================================================================== ---- /dev/null -+++ qemu-kvm-0.10/qemu/vnc-auth-sasl.c -@@ -0,0 +1,626 @@ -+/* -+ * QEMU VNC display driver: SASL auth protocol -+ * -+ * Copyright (C) 2009 Red Hat, Inc -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a copy -+ * of this software and associated documentation files (the "Software"), to deal -+ * in the Software without restriction, including without limitation the rights -+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -+ * copies of the Software, and to permit persons to whom the Software is -+ * furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -+ * THE SOFTWARE. -+ */ -+ -+#include "vnc.h" -+ -+/* Max amount of data we send/recv for SASL steps to prevent DOS */ -+#define SASL_DATA_MAX_LEN (1024 * 1024) -+ -+ -+void vnc_sasl_client_cleanup(VncState *vs) -+{ -+ if (vs->sasl.conn) { -+ vs->sasl.runSSF = vs->sasl.waitWriteSSF = vs->sasl.wantSSF = 0; -+ vs->sasl.encodedLength = vs->sasl.encodedOffset = 0; -+ vs->sasl.encoded = NULL; -+ free(vs->sasl.username); -+ free(vs->sasl.mechlist); -+ vs->sasl.username = vs->sasl.mechlist = NULL; -+ sasl_dispose(&vs->sasl.conn); -+ vs->sasl.conn = NULL; -+ } -+} -+ -+ -+long vnc_client_write_sasl(VncState *vs) -+{ -+ long ret; -+ -+ VNC_DEBUG("Write SASL: Pending output %p size %d offset %d Encoded: %p size %d offset %d\n", -+ vs->output.buffer, vs->output.capacity, vs->output.offset, -+ vs->sasl.encoded, vs->sasl.encodedLength, vs->sasl.encodedOffset); -+ -+ if (!vs->sasl.encoded) { -+ int err; -+ err = sasl_encode(vs->sasl.conn, -+ (char *)vs->output.buffer, -+ vs->output.offset, -+ (const char **)&vs->sasl.encoded, -+ &vs->sasl.encodedLength); -+ if (err != SASL_OK) -+ return vnc_client_io_error(vs, -1, EIO); -+ -+ vs->sasl.encodedOffset = 0; -+ } -+ -+ ret = vnc_client_write_buf(vs, -+ vs->sasl.encoded + vs->sasl.encodedOffset, -+ vs->sasl.encodedLength - vs->sasl.encodedOffset); -+ if (!ret) -+ return 0; -+ -+ vs->sasl.encodedOffset += ret; -+ if (vs->sasl.encodedOffset == vs->sasl.encodedLength) { -+ vs->output.offset = 0; -+ vs->sasl.encoded = NULL; -+ vs->sasl.encodedOffset = vs->sasl.encodedLength = 0; -+ } -+ -+ /* Can't merge this block with one above, because -+ * someone might have written more unencrypted -+ * data in vs->output while we were processing -+ * SASL encoded output -+ */ -+ if (vs->output.offset == 0) { -+ qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs); -+ } -+ -+ return ret; -+} -+ -+ -+long vnc_client_read_sasl(VncState *vs) -+{ -+ long ret; -+ uint8_t encoded[4096]; -+ const char *decoded; -+ unsigned int decodedLen; -+ int err; -+ -+ ret = vnc_client_read_buf(vs, encoded, sizeof(encoded)); -+ if (!ret) -+ return 0; -+ -+ err = sasl_decode(vs->sasl.conn, -+ (char *)encoded, ret, -+ &decoded, &decodedLen); -+ -+ if (err != SASL_OK) -+ return vnc_client_io_error(vs, -1, -EIO); -+ VNC_DEBUG("Read SASL Encoded %p size %ld Decoded %p size %d\n", -+ encoded, ret, decoded, decodedLen); -+ buffer_reserve(&vs->input, decodedLen); -+ buffer_append(&vs->input, decoded, decodedLen); -+ return decodedLen; -+} -+ -+ -+static int vnc_auth_sasl_check_access(VncState *vs) -+{ -+ const void *val; -+ int err; -+ -+ err = sasl_getprop(vs->sasl.conn, SASL_USERNAME, &val); -+ if (err != SASL_OK) { -+ VNC_DEBUG("cannot query SASL username on connection %d (%s)\n", -+ err, sasl_errstring(err, NULL, NULL)); -+ return -1; -+ } -+ if (val == NULL) { -+ VNC_DEBUG("no client username was found\n"); -+ return -1; -+ } -+ VNC_DEBUG("SASL client username %s\n", (const char *)val); -+ -+ vs->sasl.username = qemu_strdup((const char*)val); -+ -+ return 0; -+} -+ -+static int vnc_auth_sasl_check_ssf(VncState *vs) -+{ -+ const void *val; -+ int err, ssf; -+ -+ if (!vs->sasl.wantSSF) -+ return 1; -+ -+ err = sasl_getprop(vs->sasl.conn, SASL_SSF, &val); -+ if (err != SASL_OK) -+ return 0; -+ -+ ssf = *(const int *)val; -+ VNC_DEBUG("negotiated an SSF of %d\n", ssf); -+ if (ssf < 56) -+ return 0; /* 56 is good for Kerberos */ -+ -+ /* Only setup for read initially, because we're about to send an RPC -+ * reply which must be in plain text. When the next incoming RPC -+ * arrives, we'll switch on writes too -+ * -+ * cf qemudClientReadSASL in qemud.c -+ */ -+ vs->sasl.runSSF = 1; -+ -+ /* We have a SSF that's good enough */ -+ return 1; -+} -+ -+/* -+ * Step Msg -+ * -+ * Input from client: -+ * -+ * u32 clientin-length -+ * u8-array clientin-string -+ * -+ * Output to client: -+ * -+ * u32 serverout-length -+ * u8-array serverout-strin -+ * u8 continue -+ */ -+ -+static int protocol_client_auth_sasl_step_len(VncState *vs, uint8_t *data, size_t len); -+ -+static int protocol_client_auth_sasl_step(VncState *vs, uint8_t *data, size_t len) -+{ -+ uint32_t datalen = len; -+ const char *serverout; -+ unsigned int serveroutlen; -+ int err; -+ char *clientdata = NULL; -+ -+ /* NB, distinction of NULL vs "" is *critical* in SASL */ -+ if (datalen) { -+ clientdata = (char*)data; -+ clientdata[datalen-1] = '\0'; /* Wire includes '\0', but make sure */ -+ datalen--; /* Don't count NULL byte when passing to _start() */ -+ } -+ -+ VNC_DEBUG("Step using SASL Data %p (%d bytes)\n", -+ clientdata, datalen); -+ err = sasl_server_step(vs->sasl.conn, -+ clientdata, -+ datalen, -+ &serverout, -+ &serveroutlen); -+ if (err != SASL_OK && -+ err != SASL_CONTINUE) { -+ VNC_DEBUG("sasl step failed %d (%s)\n", -+ err, sasl_errdetail(vs->sasl.conn)); -+ sasl_dispose(&vs->sasl.conn); -+ vs->sasl.conn = NULL; -+ goto authabort; -+ } -+ -+ if (serveroutlen > SASL_DATA_MAX_LEN) { -+ VNC_DEBUG("sasl step reply data too long %d\n", -+ serveroutlen); -+ sasl_dispose(&vs->sasl.conn); -+ vs->sasl.conn = NULL; -+ goto authabort; -+ } -+ -+ VNC_DEBUG("SASL return data %d bytes, nil; %d\n", -+ serveroutlen, serverout ? 0 : 1); -+ -+ if (serveroutlen) { -+ vnc_write_u32(vs, serveroutlen + 1); -+ vnc_write(vs, serverout, serveroutlen + 1); -+ } else { -+ vnc_write_u32(vs, 0); -+ } -+ -+ /* Whether auth is complete */ -+ vnc_write_u8(vs, err == SASL_CONTINUE ? 0 : 1); -+ -+ if (err == SASL_CONTINUE) { -+ VNC_DEBUG("%s", "Authentication must continue\n"); -+ /* Wait for step length */ -+ vnc_read_when(vs, protocol_client_auth_sasl_step_len, 4); -+ } else { -+ if (!vnc_auth_sasl_check_ssf(vs)) { -+ VNC_DEBUG("Authentication rejected for weak SSF %d\n", vs->csock); -+ goto authreject; -+ } -+ -+ /* Check username whitelist ACL */ -+ if (vnc_auth_sasl_check_access(vs) < 0) { -+ VNC_DEBUG("Authentication rejected for ACL %d\n", vs->csock); -+ goto authreject; -+ } -+ -+ VNC_DEBUG("Authentication successful %d\n", vs->csock); -+ vnc_write_u32(vs, 0); /* Accept auth */ -+ /* -+ * Delay writing in SSF encoded mode until pending output -+ * buffer is written -+ */ -+ if (vs->sasl.runSSF) -+ vs->sasl.waitWriteSSF = vs->output.offset; -+ start_client_init(vs); -+ } -+ -+ return 0; -+ -+ authreject: -+ vnc_write_u32(vs, 1); /* Reject auth */ -+ vnc_write_u32(vs, sizeof("Authentication failed")); -+ vnc_write(vs, "Authentication failed", sizeof("Authentication failed")); -+ vnc_flush(vs); -+ vnc_client_error(vs); -+ return -1; -+ -+ authabort: -+ vnc_client_error(vs); -+ return -1; -+} -+ -+static int protocol_client_auth_sasl_step_len(VncState *vs, uint8_t *data, size_t len) -+{ -+ uint32_t steplen = read_u32(data, 0); -+ VNC_DEBUG("Got client step len %d\n", steplen); -+ if (steplen > SASL_DATA_MAX_LEN) { -+ VNC_DEBUG("Too much SASL data %d\n", steplen); -+ vnc_client_error(vs); -+ return -1; -+ } -+ -+ if (steplen == 0) -+ return protocol_client_auth_sasl_step(vs, NULL, 0); -+ else -+ vnc_read_when(vs, protocol_client_auth_sasl_step, steplen); -+ return 0; -+} -+ -+/* -+ * Start Msg -+ * -+ * Input from client: -+ * -+ * u32 clientin-length -+ * u8-array clientin-string -+ * -+ * Output to client: -+ * -+ * u32 serverout-length -+ * u8-array serverout-strin -+ * u8 continue -+ */ -+ -+#define SASL_DATA_MAX_LEN (1024 * 1024) -+ -+static int protocol_client_auth_sasl_start(VncState *vs, uint8_t *data, size_t len) -+{ -+ uint32_t datalen = len; -+ const char *serverout; -+ unsigned int serveroutlen; -+ int err; -+ char *clientdata = NULL; -+ -+ /* NB, distinction of NULL vs "" is *critical* in SASL */ -+ if (datalen) { -+ clientdata = (char*)data; -+ clientdata[datalen-1] = '\0'; /* Should be on wire, but make sure */ -+ datalen--; /* Don't count NULL byte when passing to _start() */ -+ } -+ -+ VNC_DEBUG("Start SASL auth with mechanism %s. Data %p (%d bytes)\n", -+ vs->sasl.mechlist, clientdata, datalen); -+ err = sasl_server_start(vs->sasl.conn, -+ vs->sasl.mechlist, -+ clientdata, -+ datalen, -+ &serverout, -+ &serveroutlen); -+ if (err != SASL_OK && -+ err != SASL_CONTINUE) { -+ VNC_DEBUG("sasl start failed %d (%s)\n", -+ err, sasl_errdetail(vs->sasl.conn)); -+ sasl_dispose(&vs->sasl.conn); -+ vs->sasl.conn = NULL; -+ goto authabort; -+ } -+ if (serveroutlen > SASL_DATA_MAX_LEN) { -+ VNC_DEBUG("sasl start reply data too long %d\n", -+ serveroutlen); -+ sasl_dispose(&vs->sasl.conn); -+ vs->sasl.conn = NULL; -+ goto authabort; -+ } -+ -+ VNC_DEBUG("SASL return data %d bytes, nil; %d\n", -+ serveroutlen, serverout ? 0 : 1); -+ -+ if (serveroutlen) { -+ vnc_write_u32(vs, serveroutlen + 1); -+ vnc_write(vs, serverout, serveroutlen + 1); -+ } else { -+ vnc_write_u32(vs, 0); -+ } -+ -+ /* Whether auth is complete */ -+ vnc_write_u8(vs, err == SASL_CONTINUE ? 0 : 1); -+ -+ if (err == SASL_CONTINUE) { -+ VNC_DEBUG("%s", "Authentication must continue\n"); -+ /* Wait for step length */ -+ vnc_read_when(vs, protocol_client_auth_sasl_step_len, 4); -+ } else { -+ if (!vnc_auth_sasl_check_ssf(vs)) { -+ VNC_DEBUG("Authentication rejected for weak SSF %d\n", vs->csock); -+ goto authreject; -+ } -+ -+ /* Check username whitelist ACL */ -+ if (vnc_auth_sasl_check_access(vs) < 0) { -+ VNC_DEBUG("Authentication rejected for ACL %d\n", vs->csock); -+ goto authreject; -+ } -+ -+ VNC_DEBUG("Authentication successful %d\n", vs->csock); -+ vnc_write_u32(vs, 0); /* Accept auth */ -+ start_client_init(vs); -+ } -+ -+ return 0; -+ -+ authreject: -+ vnc_write_u32(vs, 1); /* Reject auth */ -+ vnc_write_u32(vs, sizeof("Authentication failed")); -+ vnc_write(vs, "Authentication failed", sizeof("Authentication failed")); -+ vnc_flush(vs); -+ vnc_client_error(vs); -+ return -1; -+ -+ authabort: -+ vnc_client_error(vs); -+ return -1; -+} -+ -+static int protocol_client_auth_sasl_start_len(VncState *vs, uint8_t *data, size_t len) -+{ -+ uint32_t startlen = read_u32(data, 0); -+ VNC_DEBUG("Got client start len %d\n", startlen); -+ if (startlen > SASL_DATA_MAX_LEN) { -+ VNC_DEBUG("Too much SASL data %d\n", startlen); -+ vnc_client_error(vs); -+ return -1; -+ } -+ -+ if (startlen == 0) -+ return protocol_client_auth_sasl_start(vs, NULL, 0); -+ -+ vnc_read_when(vs, protocol_client_auth_sasl_start, startlen); -+ return 0; -+} -+ -+static int protocol_client_auth_sasl_mechname(VncState *vs, uint8_t *data, size_t len) -+{ -+ char *mechname = malloc(len + 1); -+ if (!mechname) { -+ VNC_DEBUG("Out of memory reading mechname\n"); -+ vnc_client_error(vs); -+ } -+ strncpy(mechname, (char*)data, len); -+ mechname[len] = '\0'; -+ VNC_DEBUG("Got client mechname '%s' check against '%s'\n", -+ mechname, vs->sasl.mechlist); -+ -+ if (strncmp(vs->sasl.mechlist, mechname, len) == 0) { -+ if (vs->sasl.mechlist[len] != '\0' && -+ vs->sasl.mechlist[len] != ',') { -+ VNC_DEBUG("One %d", vs->sasl.mechlist[len]); -+ vnc_client_error(vs); -+ return -1; -+ } -+ } else { -+ char *offset = strstr(vs->sasl.mechlist, mechname); -+ VNC_DEBUG("Two %p\n", offset); -+ if (!offset) { -+ vnc_client_error(vs); -+ return -1; -+ } -+ VNC_DEBUG("Two '%s'\n", offset); -+ if (offset[-1] != ',' || -+ (offset[len] != '\0'&& -+ offset[len] != ',')) { -+ vnc_client_error(vs); -+ return -1; -+ } -+ } -+ -+ free(vs->sasl.mechlist); -+ vs->sasl.mechlist = mechname; -+ -+ VNC_DEBUG("Validated mechname '%s'\n", mechname); -+ vnc_read_when(vs, protocol_client_auth_sasl_start_len, 4); -+ return 0; -+} -+ -+static int protocol_client_auth_sasl_mechname_len(VncState *vs, uint8_t *data, size_t len) -+{ -+ uint32_t mechlen = read_u32(data, 0); -+ VNC_DEBUG("Got client mechname len %d\n", mechlen); -+ if (mechlen > 100) { -+ VNC_DEBUG("Too long SASL mechname data %d\n", mechlen); -+ vnc_client_error(vs); -+ return -1; -+ } -+ if (mechlen < 1) { -+ VNC_DEBUG("Too short SASL mechname %d\n", mechlen); -+ vnc_client_error(vs); -+ return -1; -+ } -+ vnc_read_when(vs, protocol_client_auth_sasl_mechname,mechlen); -+ return 0; -+} -+ -+#define USES_X509_AUTH(vs) \ -+ ((vs)->subauth == VNC_AUTH_VENCRYPT_X509NONE || \ -+ (vs)->subauth == VNC_AUTH_VENCRYPT_X509VNC || \ -+ (vs)->subauth == VNC_AUTH_VENCRYPT_X509PLAIN || \ -+ (vs)->subauth == VNC_AUTH_VENCRYPT_X509SASL) -+ -+ -+void start_auth_sasl(VncState *vs) -+{ -+ const char *mechlist = NULL; -+ sasl_security_properties_t secprops; -+ int err; -+ char *localAddr, *remoteAddr; -+ int mechlistlen; -+ -+ VNC_DEBUG("Initialize SASL auth %d\n", vs->csock); -+ -+ /* Get local & remote client addresses in form IPADDR;PORT */ -+ if (!(localAddr = vnc_socket_local_addr("%s;%s", vs->csock))) -+ goto authabort; -+ -+ if (!(remoteAddr = vnc_socket_remote_addr("%s;%s", vs->csock))) { -+ free(localAddr); -+ goto authabort; -+ } -+ -+ err = sasl_server_new("vnc", -+ NULL, /* FQDN - just delegates to gethostname */ -+ NULL, /* User realm */ -+ localAddr, -+ remoteAddr, -+ NULL, /* Callbacks, not needed */ -+ SASL_SUCCESS_DATA, -+ &vs->sasl.conn); -+ free(localAddr); -+ free(remoteAddr); -+ localAddr = remoteAddr = NULL; -+ -+ if (err != SASL_OK) { -+ VNC_DEBUG("sasl context setup failed %d (%s)", -+ err, sasl_errstring(err, NULL, NULL)); -+ vs->sasl.conn = NULL; -+ goto authabort; -+ } -+ -+#ifdef CONFIG_VNC_TLS -+ /* Inform SASL that we've got an external SSF layer from TLS/x509 */ -+ if (vs->vd->auth == VNC_AUTH_VENCRYPT && -+ vs->vd->subauth == VNC_AUTH_VENCRYPT_X509SASL) { -+ gnutls_cipher_algorithm_t cipher; -+ sasl_ssf_t ssf; -+ -+ cipher = gnutls_cipher_get(vs->tls.session); -+ if (!(ssf = (sasl_ssf_t)gnutls_cipher_get_key_size(cipher))) { -+ VNC_DEBUG("%s", "cannot TLS get cipher size\n"); -+ sasl_dispose(&vs->sasl.conn); -+ vs->sasl.conn = NULL; -+ goto authabort; -+ } -+ ssf *= 8; /* tls key size is bytes, sasl wants bits */ -+ -+ err = sasl_setprop(vs->sasl.conn, SASL_SSF_EXTERNAL, &ssf); -+ if (err != SASL_OK) { -+ VNC_DEBUG("cannot set SASL external SSF %d (%s)\n", -+ err, sasl_errstring(err, NULL, NULL)); -+ sasl_dispose(&vs->sasl.conn); -+ vs->sasl.conn = NULL; -+ goto authabort; -+ } -+ } else -+#endif /* CONFIG_VNC_TLS */ -+ vs->sasl.wantSSF = 1; -+ -+ memset (&secprops, 0, sizeof secprops); -+ /* Inform SASL that we've got an external SSF layer from TLS */ -+ if (strncmp(vs->vd->display, "unix:", 5) == 0 -+#ifdef CONFIG_VNC_TLS -+ /* Disable SSF, if using TLS+x509+SASL only. TLS without x509 -+ is not sufficiently strong */ -+ || (vs->vd->auth == VNC_AUTH_VENCRYPT && -+ vs->vd->subauth == VNC_AUTH_VENCRYPT_X509SASL) -+#endif /* CONFIG_VNC_TLS */ -+ ) { -+ /* If we've got TLS or UNIX domain sock, we don't care about SSF */ -+ secprops.min_ssf = 0; -+ secprops.max_ssf = 0; -+ secprops.maxbufsize = 8192; -+ secprops.security_flags = 0; -+ } else { -+ /* Plain TCP, better get an SSF layer */ -+ secprops.min_ssf = 56; /* Good enough to require kerberos */ -+ secprops.max_ssf = 100000; /* Arbitrary big number */ -+ secprops.maxbufsize = 8192; -+ /* Forbid any anonymous or trivially crackable auth */ -+ secprops.security_flags = -+ SASL_SEC_NOANONYMOUS | SASL_SEC_NOPLAINTEXT; -+ } -+ -+ err = sasl_setprop(vs->sasl.conn, SASL_SEC_PROPS, &secprops); -+ if (err != SASL_OK) { -+ VNC_DEBUG("cannot set SASL security props %d (%s)\n", -+ err, sasl_errstring(err, NULL, NULL)); -+ sasl_dispose(&vs->sasl.conn); -+ vs->sasl.conn = NULL; -+ goto authabort; -+ } -+ -+ err = sasl_listmech(vs->sasl.conn, -+ NULL, /* Don't need to set user */ -+ "", /* Prefix */ -+ ",", /* Separator */ -+ "", /* Suffix */ -+ &mechlist, -+ NULL, -+ NULL); -+ if (err != SASL_OK) { -+ VNC_DEBUG("cannot list SASL mechanisms %d (%s)\n", -+ err, sasl_errdetail(vs->sasl.conn)); -+ sasl_dispose(&vs->sasl.conn); -+ vs->sasl.conn = NULL; -+ goto authabort; -+ } -+ VNC_DEBUG("Available mechanisms for client: '%s'\n", mechlist); -+ -+ if (!(vs->sasl.mechlist = strdup(mechlist))) { -+ VNC_DEBUG("Out of memory"); -+ sasl_dispose(&vs->sasl.conn); -+ vs->sasl.conn = NULL; -+ goto authabort; -+ } -+ mechlistlen = strlen(mechlist); -+ vnc_write_u32(vs, mechlistlen); -+ vnc_write(vs, mechlist, mechlistlen); -+ vnc_flush(vs); -+ -+ VNC_DEBUG("Wait for client mechname length\n"); -+ vnc_read_when(vs, protocol_client_auth_sasl_mechname_len, 4); -+ -+ return; -+ -+ authabort: -+ vnc_client_error(vs); -+ return; -+} -+ -+ -Index: qemu-kvm-0.10/qemu/vnc-auth-sasl.h -=================================================================== ---- /dev/null -+++ qemu-kvm-0.10/qemu/vnc-auth-sasl.h -@@ -0,0 +1,67 @@ -+/* -+ * QEMU VNC display driver: SASL auth protocol -+ * -+ * Copyright (C) 2009 Red Hat, Inc -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a copy -+ * of this software and associated documentation files (the "Software"), to deal -+ * in the Software without restriction, including without limitation the rights -+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -+ * copies of the Software, and to permit persons to whom the Software is -+ * furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -+ * THE SOFTWARE. -+ */ -+ -+ -+#ifndef __QEMU_VNC_AUTH_SASL_H__ -+#define __QEMU_VNC_AUTH_SASL_H__ -+ -+ -+#include -+ -+typedef struct VncStateSASL VncStateSASL; -+ -+struct VncStateSASL { -+ sasl_conn_t *conn; -+ /* If we want to negotiate an SSF layer with client */ -+ int wantSSF :1; -+ /* If we are now running the SSF layer */ -+ int runSSF :1; -+ /* -+ * If this is non-zero, then wait for that many bytes -+ * to be written plain, before switching to SSF encoding -+ * This allows the VNC auth result to finish being -+ * written in plain. -+ */ -+ unsigned int waitWriteSSF; -+ -+ /* -+ * Buffering encoded data to allow more clear data -+ * to be stuffed onto the output buffer -+ */ -+ const uint8_t *encoded; -+ unsigned int encodedLength; -+ unsigned int encodedOffset; -+ char *username; -+ char *mechlist; -+}; -+ -+void vnc_sasl_client_cleanup(VncState *vs); -+ -+long vnc_client_read_sasl(VncState *vs); -+long vnc_client_write_sasl(VncState *vs); -+ -+void start_auth_sasl(VncState *vs); -+ -+#endif /* __QEMU_VNC_AUTH_SASL_H__ */ -+ -Index: qemu-kvm-0.10/qemu/vnc-auth-vencrypt.c -=================================================================== ---- qemu-kvm-0.10.orig/qemu/vnc-auth-vencrypt.c -+++ qemu-kvm-0.10/qemu/vnc-auth-vencrypt.c -@@ -43,8 +43,15 @@ static void start_auth_vencrypt_subauth( - start_auth_vnc(vs); - break; - -+#ifdef CONFIG_VNC_SASL -+ case VNC_AUTH_VENCRYPT_TLSSASL: -+ case VNC_AUTH_VENCRYPT_X509SASL: -+ VNC_DEBUG("Start TLS auth SASL\n"); -+ return start_auth_sasl(vs); -+#endif /* CONFIG_VNC_SASL */ -+ - default: /* Should not be possible, but just in case */ -- VNC_DEBUG("Reject auth %d\n", vs->vd->auth); -+ VNC_DEBUG("Reject subauth %d server bug\n", vs->vd->auth); - vnc_write_u8(vs, 1); - if (vs->minor >= 8) { - static const char err[] = "Unsupported authentication type"; -@@ -105,7 +112,8 @@ static void vnc_tls_handshake_io(void *o - #define NEED_X509_AUTH(vs) \ - ((vs)->vd->subauth == VNC_AUTH_VENCRYPT_X509NONE || \ - (vs)->vd->subauth == VNC_AUTH_VENCRYPT_X509VNC || \ -- (vs)->vd->subauth == VNC_AUTH_VENCRYPT_X509PLAIN) -+ (vs)->vd->subauth == VNC_AUTH_VENCRYPT_X509PLAIN || \ -+ (vs)->vd->subauth == VNC_AUTH_VENCRYPT_X509SASL) - - - static int protocol_client_vencrypt_auth(VncState *vs, uint8_t *data, size_t len) -Index: qemu-kvm-0.10/qemu/vnc.c -=================================================================== ---- qemu-kvm-0.10.orig/qemu/vnc.c -+++ qemu-kvm-0.10/qemu/vnc.c -@@ -68,7 +68,8 @@ static char *addr_to_string(const char * - return addr; - } - --static char *vnc_socket_local_addr(const char *format, int fd) { -+ -+char *vnc_socket_local_addr(const char *format, int fd) { - struct sockaddr_storage sa; - socklen_t salen; - -@@ -79,7 +80,8 @@ static char *vnc_socket_local_addr(const - return addr_to_string(format, &sa, salen); - } - --static char *vnc_socket_remote_addr(const char *format, int fd) { -+ -+char *vnc_socket_remote_addr(const char *format, int fd) { - struct sockaddr_storage sa; - socklen_t salen; - -@@ -125,12 +127,18 @@ static const char *vnc_auth_name(VncDisp - return "vencrypt+x509+vnc"; - case VNC_AUTH_VENCRYPT_X509PLAIN: - return "vencrypt+x509+plain"; -+ case VNC_AUTH_VENCRYPT_TLSSASL: -+ return "vencrypt+tls+sasl"; -+ case VNC_AUTH_VENCRYPT_X509SASL: -+ return "vencrypt+x509+sasl"; - default: - return "vencrypt"; - } - #else - return "vencrypt"; - #endif -+ case VNC_AUTH_SASL: -+ return "sasl"; - } - return "unknown"; - } -@@ -278,7 +286,7 @@ static void vnc_framebuffer_update(VncSt - vnc_write_s32(vs, encoding); - } - --static void buffer_reserve(Buffer *buffer, size_t len) -+void buffer_reserve(Buffer *buffer, size_t len) - { - if ((buffer->capacity - buffer->offset) < len) { - buffer->capacity += (len + 1024); -@@ -290,22 +298,22 @@ static void buffer_reserve(Buffer *buffe - } - } - --static int buffer_empty(Buffer *buffer) -+int buffer_empty(Buffer *buffer) - { - return buffer->offset == 0; - } - --static uint8_t *buffer_end(Buffer *buffer) -+uint8_t *buffer_end(Buffer *buffer) - { - return buffer->buffer + buffer->offset; - } - --static void buffer_reset(Buffer *buffer) -+void buffer_reset(Buffer *buffer) - { - buffer->offset = 0; - } - --static void buffer_append(Buffer *buffer, const void *data, size_t len) -+void buffer_append(Buffer *buffer, const void *data, size_t len) - { - memcpy(buffer->buffer + buffer->offset, data, len); - buffer->offset += len; -@@ -821,7 +829,8 @@ static void audio_del(VncState *vs) - } - } - --static int vnc_client_io_error(VncState *vs, int ret, int last_errno) -+ -+int vnc_client_io_error(VncState *vs, int ret, int last_errno) - { - if (ret == 0 || ret == -1) { - if (ret == -1) { -@@ -847,6 +856,9 @@ static int vnc_client_io_error(VncState - #ifdef CONFIG_VNC_TLS - vnc_tls_client_cleanup(vs); - #endif /* CONFIG_VNC_TLS */ -+#ifdef CONFIG_VNC_SASL -+ vnc_sasl_client_cleanup(vs); -+#endif /* CONFIG_VNC_SASL */ - audio_del(vs); - - VncState *p, *parent = NULL; -@@ -877,14 +889,28 @@ void vnc_client_error(VncState *vs) - vnc_client_io_error(vs, -1, EINVAL); - } - --void vnc_client_write(void *opaque) -+ -+/* -+ * Called to write a chunk of data to the client socket. The data may -+ * be the raw data, or may have already been encoded by SASL. -+ * The data will be written either straight onto the socket, or -+ * written via the GNUTLS wrappers, if TLS/SSL encryption is enabled -+ * -+ * NB, it is theoretically possible to have 2 layers of encryption, -+ * both SASL, and this TLS layer. It is highly unlikely in practice -+ * though, since SASL encryption will typically be a no-op if TLS -+ * is active -+ * -+ * Returns the number of bytes written, which may be less than -+ * the requested 'datalen' if the socket would block. Returns -+ * -1 on error, and disconnects the client socket. -+ */ -+long vnc_client_write_buf(VncState *vs, const uint8_t *data, size_t datalen) - { - long ret; -- VncState *vs = opaque; -- - #ifdef CONFIG_VNC_TLS - if (vs->tls.session) { -- ret = gnutls_write(vs->tls.session, vs->output.buffer, vs->output.offset); -+ ret = gnutls_write(vs->tls.session, data, datalen); - if (ret < 0) { - if (ret == GNUTLS_E_AGAIN) - errno = EAGAIN; -@@ -894,10 +920,42 @@ void vnc_client_write(void *opaque) - } - } else - #endif /* CONFIG_VNC_TLS */ -- ret = send(vs->csock, vs->output.buffer, vs->output.offset, 0); -- ret = vnc_client_io_error(vs, ret, socket_error()); -+ ret = send(vs->csock, data, datalen, 0); -+ VNC_DEBUG("Wrote wire %p %d -> %ld\n", data, datalen, ret); -+ return vnc_client_io_error(vs, ret, socket_error()); -+} -+ -+ -+/* -+ * Called to write buffered data to the client socket, when not -+ * using any SASL SSF encryption layers. Will write as much data -+ * as possible without blocking. If all buffered data is written, -+ * will switch the FD poll() handler back to read monitoring. -+ * -+ * Returns the number of bytes written, which may be less than -+ * the buffered output data if the socket would block. Returns -+ * -1 on error, and disconnects the client socket. -+ */ -+static long vnc_client_write_plain(VncState *vs) -+{ -+ long ret; -+ -+#ifdef CONFIG_VNC_SASL -+ VNC_DEBUG("Write Plain: Pending output %p size %d offset %d. Wait SSF %d\n", -+ vs->output.buffer, vs->output.capacity, vs->output.offset, -+ vs->sasl.waitWriteSSF); -+ -+ if (vs->sasl.conn && -+ vs->sasl.runSSF && -+ vs->sasl.waitWriteSSF) { -+ ret = vnc_client_write_buf(vs, vs->output.buffer, vs->sasl.waitWriteSSF); -+ if (ret) -+ vs->sasl.waitWriteSSF -= ret; -+ } else -+#endif /* CONFIG_VNC_SASL */ -+ ret = vnc_client_write_buf(vs, vs->output.buffer, vs->output.offset); - if (!ret) -- return; -+ return 0; - - memmove(vs->output.buffer, vs->output.buffer + ret, (vs->output.offset - ret)); - vs->output.offset -= ret; -@@ -905,6 +963,29 @@ void vnc_client_write(void *opaque) - if (vs->output.offset == 0) { - qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs); - } -+ -+ return ret; -+} -+ -+ -+/* -+ * First function called whenever there is data to be written to -+ * the client socket. Will delegate actual work according to whether -+ * SASL SSF layers are enabled (thus requiring encryption calls) -+ */ -+void vnc_client_write(void *opaque) -+{ -+ long ret; -+ VncState *vs = opaque; -+ -+#ifdef CONFIG_VNC_SASL -+ if (vs->sasl.conn && -+ vs->sasl.runSSF && -+ !vs->sasl.waitWriteSSF) -+ ret = vnc_client_write_sasl(vs); -+ else -+#endif /* CONFIG_VNC_SASL */ -+ ret = vnc_client_write_plain(vs); - } - - void vnc_read_when(VncState *vs, VncReadEvent *func, size_t expecting) -@@ -913,16 +994,28 @@ void vnc_read_when(VncState *vs, VncRead - vs->read_handler_expect = expecting; - } - --void vnc_client_read(void *opaque) -+ -+/* -+ * Called to read a chunk of data from the client socket. The data may -+ * be the raw data, or may need to be further decoded by SASL. -+ * The data will be read either straight from to the socket, or -+ * read via the GNUTLS wrappers, if TLS/SSL encryption is enabled -+ * -+ * NB, it is theoretically possible to have 2 layers of encryption, -+ * both SASL, and this TLS layer. It is highly unlikely in practice -+ * though, since SASL encryption will typically be a no-op if TLS -+ * is active -+ * -+ * Returns the number of bytes read, which may be less than -+ * the requested 'datalen' if the socket would block. Returns -+ * -1 on error, and disconnects the client socket. -+ */ -+long vnc_client_read_buf(VncState *vs, uint8_t *data, size_t datalen) - { -- VncState *vs = opaque; - long ret; -- -- buffer_reserve(&vs->input, 4096); -- - #ifdef CONFIG_VNC_TLS - if (vs->tls.session) { -- ret = gnutls_read(vs->tls.session, buffer_end(&vs->input), 4096); -+ ret = gnutls_read(vs->tls.session, data, datalen); - if (ret < 0) { - if (ret == GNUTLS_E_AGAIN) - errno = EAGAIN; -@@ -932,12 +1025,52 @@ void vnc_client_read(void *opaque) - } - } else - #endif /* CONFIG_VNC_TLS */ -- ret = recv(vs->csock, buffer_end(&vs->input), 4096, 0); -- ret = vnc_client_io_error(vs, ret, socket_error()); -- if (!ret) -- return; -+ ret = recv(vs->csock, data, datalen, 0); -+ VNC_DEBUG("Read wire %p %d -> %ld\n", data, datalen, ret); -+ return vnc_client_io_error(vs, ret, socket_error()); -+} - -+ -+/* -+ * Called to read data from the client socket to the input buffer, -+ * when not using any SASL SSF encryption layers. Will read as much -+ * data as possible without blocking. -+ * -+ * Returns the number of bytes read. Returns -1 on error, and -+ * disconnects the client socket. -+ */ -+static long vnc_client_read_plain(VncState *vs) -+{ -+ int ret; -+ VNC_DEBUG("Read plain %p size %d offset %d\n", -+ vs->input.buffer, vs->input.capacity, vs->input.offset); -+ buffer_reserve(&vs->input, 4096); -+ ret = vnc_client_read_buf(vs, buffer_end(&vs->input), 4096); -+ if (!ret) -+ return 0; - vs->input.offset += ret; -+ return ret; -+} -+ -+ -+/* -+ * First function called whenever there is more data to be read from -+ * the client socket. Will delegate actual work according to whether -+ * SASL SSF layers are enabled (thus requiring decryption calls) -+ */ -+void vnc_client_read(void *opaque) -+{ -+ VncState *vs = opaque; -+ long ret; -+ -+#ifdef CONFIG_VNC_SASL -+ if (vs->sasl.conn && vs->sasl.runSSF) -+ ret = vnc_client_read_sasl(vs); -+ else -+#endif /* CONFIG_VNC_SASL */ -+ ret = vnc_client_read_plain(vs); -+ if (!ret) -+ return; - - while (vs->read_handler && vs->input.offset >= vs->read_handler_expect) { - size_t len = vs->read_handler_expect; -@@ -1722,6 +1855,13 @@ static int protocol_client_auth(VncState - break; - #endif /* CONFIG_VNC_TLS */ - -+#ifdef CONFIG_VNC_SASL -+ case VNC_AUTH_SASL: -+ VNC_DEBUG("Accept SASL auth\n"); -+ start_auth_sasl(vs); -+ break; -+#endif /* CONFIG_VNC_SASL */ -+ - default: /* Should not be possible, but just in case */ - VNC_DEBUG("Reject auth %d\n", vs->vd->auth); - vnc_write_u8(vs, 1); -@@ -1923,6 +2063,10 @@ int vnc_display_open(DisplayState *ds, c - #ifdef CONFIG_VNC_TLS - int tls = 0, x509 = 0; - #endif -+#ifdef CONFIG_VNC_SASL -+ int sasl = 0; -+ int saslErr; -+#endif - - if (!vnc_display) - return -1; -@@ -1942,6 +2086,10 @@ int vnc_display_open(DisplayState *ds, c - reverse = 1; - } else if (strncmp(options, "to=", 3) == 0) { - to_port = atoi(options+3) + 5900; -+#ifdef CONFIG_VNC_SASL -+ } else if (strncmp(options, "sasl", 4) == 0) { -+ sasl = 1; /* Require SASL auth */ -+#endif - #ifdef CONFIG_VNC_TLS - } else if (strncmp(options, "tls", 3) == 0) { - tls = 1; /* Require TLS */ -@@ -1978,6 +2126,22 @@ int vnc_display_open(DisplayState *ds, c - } - } - -+ /* -+ * Combinations we support here: -+ * -+ * - no-auth (clear text, no auth) -+ * - password (clear text, weak auth) -+ * - sasl (encrypt, good auth *IF* using Kerberos via GSSAPI) -+ * - tls (encrypt, weak anonymous creds, no auth) -+ * - tls + password (encrypt, weak anonymous creds, weak auth) -+ * - tls + sasl (encrypt, weak anonymous creds, good auth) -+ * - tls + x509 (encrypt, good x509 creds, no auth) -+ * - tls + x509 + password (encrypt, good x509 creds, weak auth) -+ * - tls + x509 + sasl (encrypt, good x509 creds, good auth) -+ * -+ * NB1. TLS is a stackable auth scheme. -+ * NB2. the x509 schemes have option to validate a client cert dname -+ */ - if (password) { - #ifdef CONFIG_VNC_TLS - if (tls) { -@@ -1990,13 +2154,34 @@ int vnc_display_open(DisplayState *ds, c - vs->subauth = VNC_AUTH_VENCRYPT_TLSVNC; - } - } else { --#endif -+#endif /* CONFIG_VNC_TLS */ - VNC_DEBUG("Initializing VNC server with password auth\n"); - vs->auth = VNC_AUTH_VNC; - #ifdef CONFIG_VNC_TLS - vs->subauth = VNC_AUTH_INVALID; - } --#endif -+#endif /* CONFIG_VNC_TLS */ -+#ifdef CONFIG_VNC_SASL -+ } else if (sasl) { -+#ifdef CONFIG_VNC_TLS -+ if (tls) { -+ vs->auth = VNC_AUTH_VENCRYPT; -+ if (x509) { -+ VNC_DEBUG("Initializing VNC server with x509 SASL auth\n"); -+ vs->subauth = VNC_AUTH_VENCRYPT_X509SASL; -+ } else { -+ VNC_DEBUG("Initializing VNC server with TLS SASL auth\n"); -+ vs->subauth = VNC_AUTH_VENCRYPT_TLSSASL; -+ } -+ } else { -+#endif /* CONFIG_VNC_TLS */ -+ VNC_DEBUG("Initializing VNC server with SASL auth\n"); -+ vs->auth = VNC_AUTH_SASL; -+#ifdef CONFIG_VNC_TLS -+ vs->subauth = VNC_AUTH_INVALID; -+ } -+#endif /* CONFIG_VNC_TLS */ -+#endif /* CONFIG_VNC_SASL */ - } else { - #ifdef CONFIG_VNC_TLS - if (tls) { -@@ -2018,6 +2203,16 @@ int vnc_display_open(DisplayState *ds, c - #endif - } - -+#ifdef CONFIG_VNC_SASL -+ if ((saslErr = sasl_server_init(NULL, "qemu")) != SASL_OK) { -+ fprintf(stderr, "Failed to initialize SASL auth %s", -+ sasl_errstring(saslErr, NULL, NULL)); -+ free(vs->display); -+ vs->display = NULL; -+ return -1; -+ } -+#endif -+ - if (reverse) { - /* connect to viewer */ - if (strncmp(display, "unix:", 5) == 0) -Index: qemu-kvm-0.10/qemu/vnc.h -=================================================================== ---- qemu-kvm-0.10.orig/qemu/vnc.h -+++ qemu-kvm-0.10/qemu/vnc.h -@@ -79,6 +79,10 @@ typedef struct VncDisplay VncDisplay; - #include "vnc-tls.h" - #include "vnc-auth-vencrypt.h" - #endif -+#ifdef CONFIG_VNC_SASL -+#include "vnc-auth-sasl.h" -+#endif -+ - - struct VncDisplay - { -@@ -118,10 +122,12 @@ struct VncState - int minor; - - char challenge[VNC_AUTH_CHALLENGE_SIZE]; -- - #ifdef CONFIG_VNC_TLS - VncStateTLS tls; - #endif -+#ifdef CONFIG_VNC_SASL -+ VncStateSASL sasl; -+#endif - - Buffer output; - Buffer input; -@@ -160,8 +166,9 @@ enum { - VNC_AUTH_RA2NE = 6, - VNC_AUTH_TIGHT = 16, - VNC_AUTH_ULTRA = 17, -- VNC_AUTH_TLS = 18, -- VNC_AUTH_VENCRYPT = 19 -+ VNC_AUTH_TLS = 18, /* Supported in GTK-VNC & VINO */ -+ VNC_AUTH_VENCRYPT = 19, /* Supported in GTK-VNC & VeNCrypt */ -+ VNC_AUTH_SASL = 20, /* Supported in GTK-VNC & VINO */ - }; - - enum { -@@ -172,6 +179,8 @@ enum { - VNC_AUTH_VENCRYPT_X509NONE = 260, - VNC_AUTH_VENCRYPT_X509VNC = 261, - VNC_AUTH_VENCRYPT_X509PLAIN = 262, -+ VNC_AUTH_VENCRYPT_X509SASL = 263, -+ VNC_AUTH_VENCRYPT_TLSSASL = 264, - }; - - -@@ -255,6 +264,8 @@ enum { - void vnc_client_read(void *opaque); - void vnc_client_write(void *opaque); - -+long vnc_client_read_buf(VncState *vs, uint8_t *data, size_t datalen); -+long vnc_client_write_buf(VncState *vs, const uint8_t *data, size_t datalen); - - /* Protocol I/O functions */ - void vnc_write(VncState *vs, const void *data, size_t len); -@@ -274,8 +285,22 @@ uint32_t read_u32(uint8_t *data, size_t - - /* Protocol stage functions */ - void vnc_client_error(VncState *vs); -+int vnc_client_io_error(VncState *vs, int ret, int last_errno); - - void start_client_init(VncState *vs); - void start_auth_vnc(VncState *vs); - -+/* Buffer management */ -+void buffer_reserve(Buffer *buffer, size_t len); -+int buffer_empty(Buffer *buffer); -+uint8_t *buffer_end(Buffer *buffer); -+void buffer_reset(Buffer *buffer); -+void buffer_append(Buffer *buffer, const void *data, size_t len); -+ -+ -+/* Misc helpers */ -+ -+char *vnc_socket_local_addr(const char *format, int fd); -+char *vnc_socket_remote_addr(const char *format, int fd); -+ - #endif /* __QEMU_VNC_H */ diff --git a/07-vnc-monitor-authinfo.patch b/07-vnc-monitor-authinfo.patch deleted file mode 100644 index f691c7e..0000000 --- a/07-vnc-monitor-authinfo.patch +++ /dev/null @@ -1,93 +0,0 @@ -Index: qemu-kvm-0.10/qemu/vnc-tls.c -=================================================================== ---- qemu-kvm-0.10.orig/qemu/vnc-tls.c -+++ qemu-kvm-0.10/qemu/vnc-tls.c -@@ -241,6 +241,22 @@ int vnc_tls_validate_certificate(struct - return -1; - } - -+ if (i == 0) { -+ size_t dnameSize = 1024; -+ vs->tls.dname = qemu_malloc(dnameSize); -+ requery: -+ if ((ret = gnutls_x509_crt_get_dn (cert, vs->tls.dname, &dnameSize)) != 0) { -+ if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER) { -+ vs->tls.dname = qemu_realloc(vs->tls.dname, dnameSize); -+ goto requery; -+ } -+ gnutls_x509_crt_deinit (cert); -+ VNC_DEBUG("Cannot get client distinguished name: %s", -+ gnutls_strerror (ret)); -+ return -1; -+ } -+ } -+ - gnutls_x509_crt_deinit (cert); - } - -@@ -347,6 +363,7 @@ void vnc_tls_client_cleanup(struct VncSt - vs->tls.session = NULL; - } - vs->tls.wiremode = VNC_WIREMODE_CLEAR; -+ free(vs->tls.dname); - } - - -Index: qemu-kvm-0.10/qemu/vnc-tls.h -=================================================================== ---- qemu-kvm-0.10.orig/qemu/vnc-tls.h -+++ qemu-kvm-0.10/qemu/vnc-tls.h -@@ -55,6 +55,9 @@ struct VncStateTLS { - /* Whether data is being TLS encrypted yet */ - int wiremode; - gnutls_session_t session; -+ -+ /* Client's Distinguished Name from the x509 cert */ -+ char *dname; - }; - - int vnc_tls_client_setup(VncState *vs, int x509Creds); -Index: qemu-kvm-0.10/qemu/vnc.c -=================================================================== ---- qemu-kvm-0.10.orig/qemu/vnc.c -+++ qemu-kvm-0.10/qemu/vnc.c -@@ -156,6 +156,21 @@ static void do_info_vnc_client(VncState - term_puts("Client:\n"); - term_puts(clientAddr); - free(clientAddr); -+ -+#ifdef CONFIG_VNC_TLS -+ if (client->tls.session && -+ client->tls.dname) -+ term_printf(" x509 dname: %s\n", client->tls.dname); -+ else -+ term_puts(" x509 dname: none\n"); -+#endif -+#ifdef CONFIG_VNC_SASL -+ if (client->sasl.conn && -+ client->sasl.username) -+ term_printf(" username: %s\n", client->sasl.username); -+ else -+ term_puts(" username: none\n"); -+#endif - } - - void do_info_vnc(void) -@@ -1823,7 +1838,7 @@ static int protocol_client_auth(VncState - /* We only advertise 1 auth scheme at a time, so client - * must pick the one we sent. Verify this */ - if (data[0] != vs->vd->auth) { /* Reject auth */ -- VNC_DEBUG("Reject auth %d\n", (int)data[0]); -+ VNC_DEBUG("Reject auth %d because it didn't match advertized\n", (int)data[0]); - vnc_write_u32(vs, 1); - if (vs->minor >= 8) { - static const char err[] = "Authentication failed"; -@@ -1863,7 +1878,7 @@ static int protocol_client_auth(VncState - #endif /* CONFIG_VNC_SASL */ - - default: /* Should not be possible, but just in case */ -- VNC_DEBUG("Reject auth %d\n", vs->vd->auth); -+ VNC_DEBUG("Reject auth %d server code bug\n", vs->vd->auth); - vnc_write_u8(vs, 1); - if (vs->minor >= 8) { - static const char err[] = "Authentication failed"; diff --git a/08-vnc-acl-mgmt.patch b/08-vnc-acl-mgmt.patch deleted file mode 100644 index a4ae11d..0000000 --- a/08-vnc-acl-mgmt.patch +++ /dev/null @@ -1,709 +0,0 @@ -Index: qemu-kvm-0.10/qemu/Makefile -=================================================================== ---- qemu-kvm-0.10.orig/qemu/Makefile -+++ qemu-kvm-0.10/qemu/Makefile -@@ -148,7 +148,7 @@ endif - ifdef CONFIG_CURSES - OBJS+=curses.o - endif --OBJS+=vnc.o d3des.o -+OBJS+=vnc.o acl.o d3des.o - ifdef CONFIG_VNC_TLS - OBJS+=vnc-tls.o vnc-auth-vencrypt.o - endif -@@ -178,9 +178,11 @@ sdl.o: sdl.c keymaps.h sdl_keysym.h - - sdl.o audio/sdlaudio.o: CFLAGS += $(SDL_CFLAGS) - -+acl.o: acl.h acl.c -+ - vnc.h: vnc-tls.h vnc-auth-vencrypt.h vnc-auth-sasl.h keymaps.h - --vnc.o: vnc.c vnc.h vnc_keysym.h vnchextile.h d3des.c d3des.h -+vnc.o: vnc.c vnc.h vnc_keysym.h vnchextile.h d3des.c d3des.h acl.h - - vnc.o: CFLAGS += $(CONFIG_VNC_TLS_CFLAGS) - -Index: qemu-kvm-0.10/qemu/acl.c -=================================================================== ---- /dev/null -+++ qemu-kvm-0.10/qemu/acl.c -@@ -0,0 +1,185 @@ -+/* -+ * QEMU access control list management -+ * -+ * Copyright (C) 2009 Red Hat, Inc -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a copy -+ * of this software and associated documentation files (the "Software"), to deal -+ * in the Software without restriction, including without limitation the rights -+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -+ * copies of the Software, and to permit persons to whom the Software is -+ * furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -+ * THE SOFTWARE. -+ */ -+ -+ -+#include "qemu-common.h" -+#include "sysemu.h" -+#include "acl.h" -+ -+#ifdef HAVE_FNMATCH_H -+#include -+#endif -+ -+ -+static unsigned int nacls = 0; -+static qemu_acl **acls = NULL; -+ -+ -+ -+qemu_acl *qemu_acl_find(const char *aclname) -+{ -+ int i; -+ for (i = 0 ; i < nacls ; i++) { -+ if (strcmp(acls[i]->aclname, aclname) == 0) -+ return acls[i]; -+ } -+ -+ return NULL; -+} -+ -+qemu_acl *qemu_acl_init(const char *aclname) -+{ -+ qemu_acl *acl; -+ -+ acl = qemu_acl_find(aclname); -+ if (acl) -+ return acl; -+ -+ acl = qemu_malloc(sizeof(*acl)); -+ acl->aclname = qemu_strdup(aclname); -+ /* Deny by default, so there is no window of "open -+ * access" between QEMU starting, and the user setting -+ * up ACLs in the monitor */ -+ acl->defaultDeny = 1; -+ -+ acl->nentries = 0; -+ TAILQ_INIT(&acl->entries); -+ -+ acls = qemu_realloc(acls, sizeof(*acls) * (nacls +1)); -+ acls[nacls] = acl; -+ nacls++; -+ -+ return acl; -+} -+ -+int qemu_acl_party_is_allowed(qemu_acl *acl, -+ const char *party) -+{ -+ qemu_acl_entry *entry; -+ -+ TAILQ_FOREACH(entry, &acl->entries, next) { -+#ifdef HAVE_FNMATCH_H -+ if (fnmatch(entry->match, party, 0) == 0) -+ return entry->deny ? 0 : 1; -+#else -+ /* No fnmatch, so fallback to exact string matching -+ * instead of allowing wildcards */ -+ if (strcmp(entry->match, party) == 0) -+ return entry->deny ? 0 : 1; -+#endif -+ } -+ -+ return acl->defaultDeny ? 0 : 1; -+} -+ -+ -+void qemu_acl_reset(qemu_acl *acl) -+{ -+ qemu_acl_entry *entry; -+ -+ /* Put back to deny by default, so there is no window -+ * of "open access" while the user re-initializes the -+ * access control list */ -+ acl->defaultDeny = 1; -+ TAILQ_FOREACH(entry, &acl->entries, next) { -+ TAILQ_REMOVE(&acl->entries, entry, next); -+ free(entry->match); -+ free(entry); -+ } -+ acl->nentries = 0; -+} -+ -+ -+int qemu_acl_append(qemu_acl *acl, -+ int deny, -+ const char *match) -+{ -+ qemu_acl_entry *entry; -+ -+ entry = qemu_malloc(sizeof(*entry)); -+ entry->match = qemu_strdup(match); -+ entry->deny = deny; -+ -+ TAILQ_INSERT_TAIL(&acl->entries, entry, next); -+ acl->nentries++; -+ -+ return acl->nentries; -+} -+ -+ -+int qemu_acl_insert(qemu_acl *acl, -+ int deny, -+ const char *match, -+ int index) -+{ -+ qemu_acl_entry *entry; -+ qemu_acl_entry *tmp; -+ int i = 0; -+ -+ if (index <= 0) -+ return -1; -+ if (index >= acl->nentries) -+ return qemu_acl_append(acl, deny, match); -+ -+ -+ entry = qemu_malloc(sizeof(*entry)); -+ entry->match = qemu_strdup(match); -+ entry->deny = deny; -+ -+ TAILQ_FOREACH(tmp, &acl->entries, next) { -+ i++; -+ if (i == index) { -+ TAILQ_INSERT_BEFORE(tmp, entry, next); -+ acl->nentries++; -+ break; -+ } -+ } -+ -+ return i; -+} -+ -+int qemu_acl_remove(qemu_acl *acl, -+ const char *match) -+{ -+ qemu_acl_entry *entry; -+ int i = 0; -+ -+ TAILQ_FOREACH(entry, &acl->entries, next) { -+ i++; -+ if (strcmp(entry->match, match) == 0) { -+ TAILQ_REMOVE(&acl->entries, entry, next); -+ return i; -+ } -+ } -+ return -1; -+} -+ -+ -+/* -+ * Local variables: -+ * c-indent-level: 4 -+ * c-basic-offset: 4 -+ * tab-width: 8 -+ * End: -+ */ -Index: qemu-kvm-0.10/qemu/acl.h -=================================================================== ---- /dev/null -+++ qemu-kvm-0.10/qemu/acl.h -@@ -0,0 +1,74 @@ -+/* -+ * QEMU access control list management -+ * -+ * Copyright (C) 2009 Red Hat, Inc -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a copy -+ * of this software and associated documentation files (the "Software"), to deal -+ * in the Software without restriction, including without limitation the rights -+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -+ * copies of the Software, and to permit persons to whom the Software is -+ * furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -+ * THE SOFTWARE. -+ */ -+ -+#ifndef __QEMU_ACL_H__ -+#define __QEMU_ACL_H__ -+ -+#include "sys-queue.h" -+ -+typedef struct qemu_acl_entry qemu_acl_entry; -+typedef struct qemu_acl qemu_acl; -+ -+struct qemu_acl_entry { -+ char *match; -+ int deny; -+ -+ TAILQ_ENTRY(qemu_acl_entry) next; -+}; -+ -+struct qemu_acl { -+ char *aclname; -+ unsigned int nentries; -+ TAILQ_HEAD(,qemu_acl_entry) entries; -+ int defaultDeny; -+}; -+ -+qemu_acl *qemu_acl_init(const char *aclname); -+ -+qemu_acl *qemu_acl_find(const char *aclname); -+ -+int qemu_acl_party_is_allowed(qemu_acl *acl, -+ const char *party); -+ -+void qemu_acl_reset(qemu_acl *acl); -+ -+int qemu_acl_append(qemu_acl *acl, -+ int deny, -+ const char *match); -+int qemu_acl_insert(qemu_acl *acl, -+ int deny, -+ const char *match, -+ int index); -+int qemu_acl_remove(qemu_acl *acl, -+ const char *match); -+ -+#endif /* __QEMU_ACL_H__ */ -+ -+/* -+ * Local variables: -+ * c-indent-level: 4 -+ * c-basic-offset: 4 -+ * tab-width: 8 -+ * End: -+ */ -Index: qemu-kvm-0.10/qemu/configure -=================================================================== ---- qemu-kvm-0.10.orig/qemu/configure -+++ qemu-kvm-0.10/qemu/configure -@@ -913,6 +913,21 @@ EOF - fi - - ########################################## -+# fnmatch() probe, used for ACL routines -+fnmatch="no" -+cat > $TMPC << EOF -+#include -+int main(void) -+{ -+ fnmatch("foo", "foo", 0); -+ return 0; -+} -+EOF -+if $cc $ARCH_CFLAGS -o $TMPE $TMPC > /dev/null 2> /dev/null ; then -+ fnmatch="yes" -+fi -+ -+########################################## - # vde libraries probe - if test "$vde" = "yes" ; then - cat > $TMPC << EOF -@@ -1501,6 +1516,9 @@ if test "$vnc_sasl" = "yes" ; then - echo "CONFIG_VNC_SASL_LIBS=$vnc_sasl_libs" >> $config_mak - echo "#define CONFIG_VNC_SASL 1" >> $config_h - fi -+if test "$fnmatch" = "yes" ; then -+ echo "#define HAVE_FNMATCH_H 1" >> $config_h -+fi - qemu_version=`head $source_path/VERSION` - echo "VERSION=$qemu_version" >>$config_mak - echo "#define QEMU_VERSION \"$qemu_version\"" >> $config_h -Index: qemu-kvm-0.10/qemu/monitor.c -=================================================================== ---- qemu-kvm-0.10.orig/qemu/monitor.c -+++ qemu-kvm-0.10/qemu/monitor.c -@@ -39,6 +39,7 @@ - #include "qemu-timer.h" - #include "migration.h" - #include "kvm.h" -+#include "acl.h" - - #include "qemu-kvm.h" - -@@ -1498,6 +1499,85 @@ static void do_info_balloon(void) - term_printf("balloon: actual=%d\n", (int)(actual >> 20)); - } - -+static void do_acl(const char *command, -+ const char *aclname, -+ const char *match, -+ int has_index, -+ int index) -+{ -+ qemu_acl *acl; -+ -+ acl = qemu_acl_find(aclname); -+ if (!acl) { -+ term_printf("acl: unknown list '%s'\n", aclname); -+ return; -+ } -+ -+ if (strcmp(command, "show") == 0) { -+ int i = 0; -+ qemu_acl_entry *entry; -+ term_printf("policy: %s\n", -+ acl->defaultDeny ? "deny" : "allow"); -+ TAILQ_FOREACH(entry, &acl->entries, next) { -+ i++; -+ term_printf("%d: %s %s\n", i, -+ entry->deny ? "deny" : "allow", -+ entry->match); -+ } -+ } else if (strcmp(command, "reset") == 0) { -+ qemu_acl_reset(acl); -+ term_printf("acl: removed all rules\n"); -+ } else if (strcmp(command, "policy") == 0) { -+ if (!match) { -+ term_printf("acl: missing policy parameter\n"); -+ return; -+ } -+ -+ if (strcmp(match, "allow") == 0) { -+ acl->defaultDeny = 0; -+ term_printf("acl: policy set to 'allow'\n"); -+ } else if (strcmp(match, "deny") == 0) { -+ acl->defaultDeny = 1; -+ term_printf("acl: policy set to 'deny'\n"); -+ } else { -+ term_printf("acl: unknown policy '%s', expected 'deny' or 'allow'\n", match); -+ } -+ } else if ((strcmp(command, "allow") == 0) || -+ (strcmp(command, "deny") == 0)) { -+ int deny = strcmp(command, "deny") == 0 ? 1 : 0; -+ int ret; -+ -+ if (!match) { -+ term_printf("acl: missing match parameter\n"); -+ return; -+ } -+ -+ if (has_index) -+ ret = qemu_acl_insert(acl, deny, match, index); -+ else -+ ret = qemu_acl_append(acl, deny, match); -+ if (ret < 0) -+ term_printf("acl: unable to add acl entry\n"); -+ else -+ term_printf("acl: added rule at position %d\n", ret); -+ } else if (strcmp(command, "remove") == 0) { -+ int ret; -+ -+ if (!match) { -+ term_printf("acl: missing match parameter\n"); -+ return; -+ } -+ -+ ret = qemu_acl_remove(acl, match); -+ if (ret < 0) -+ term_printf("acl: no matching acl entry\n"); -+ else -+ term_printf("acl: removed rule at position %d\n", ret); -+ } else { -+ term_printf("acl: unknown command '%s'\n", command); -+ } -+} -+ - /* Please update qemu-doc.texi when adding or changing commands */ - static const term_cmd_t term_cmds[] = { - { "help|?", "s?", do_help, -@@ -1603,6 +1683,12 @@ static const term_cmd_t term_cmds[] = { - { "set_link", "ss", do_set_link, - "name [up|down]", "change the link status of a network adapter" }, - { "set_link", "ss", do_set_link, "name [up|down]" }, -+ { "acl", "sss?i?", do_acl, " [] []\n", -+ "acl show vnc.username\n" -+ "acl policy vnc.username deny\n" -+ "acl allow vnc.username fred\n" -+ "acl deny vnc.username bob\n" -+ "acl reset vnc.username\n" }, - { "cpu_set", "is", do_cpu_set_nr, "cpu [online|offline]", "change cpu state" }, - #if defined(TARGET_I386) || defined(TARGET_X86_64) - { "drive_add", "iss", drive_hot_add, "pcibus pcidevfn [file=file][,if=type][,bus=n]\n" -@@ -1611,6 +1697,7 @@ static const term_cmd_t term_cmds[] = { - "[snapshot=on|off][,cache=on|off]", - "add drive to PCI storage controller" }, - #endif -+ - { NULL, NULL, }, - }; - -@@ -2995,3 +3082,12 @@ int monitor_read_bdrv_key(BlockDriverSta - } - return -EPERM; - } -+ -+ -+/* -+ * Local variables: -+ * c-indent-level: 4 -+ * c-basic-offset: 4 -+ * tab-width: 8 -+ * End: -+ */ -Index: qemu-kvm-0.10/qemu/qemu-doc.texi -=================================================================== ---- qemu-kvm-0.10.orig/qemu/qemu-doc.texi -+++ qemu-kvm-0.10/qemu/qemu-doc.texi -@@ -639,6 +639,19 @@ ensures a data encryption preventing com - credentials. See the @ref{vnc_security} section for details on using - SASL authentication. - -+@item acl -+ -+Turn on access control lists for checking of the x509 client certificate -+and SASL party. For x509 certs, the ACL check is made against the -+certificate's distinguished name. This is something that looks like -+@code{C=GB,O=ACME,L=Boston,CN=bob}. For SASL party, the ACL check is -+made against the username, which depending on the SASL plugin, may -+include a realm component, eg @code{bob} or @code{bob\@EXAMPLE.COM}. -+When the @option{acl} flag is set, the initial access list will be -+empty, with a @code{deny} policy. Thus no one will be allowed to -+use the VNC server until the ACLs have been loaded. This can be -+achieved using the @code{acl} monitor command. -+ - @end table - - @end table -@@ -1400,6 +1413,42 @@ Password: ******** - - @end table - -+@item acl @var{subcommand} @var{aclname} @var{match} @var{index} -+ -+Manage access control lists for network services. There are currently -+two named access control lists, @var{vnc.x509dname} and @var{vnc.username} -+matching on the x509 client certificate distinguished name, and SASL -+username respectively. -+ -+@table @option -+@item acl show -+list all the match rules in the access control list, and the default -+policy -+@item acl policy @code{allow|deny} -+set the default access control list policy, used in the event that -+none of the explicit rules match. The default policy at startup is -+always @code{deny} -+@item acl allow [] -+add a match to the access control list, allowing access. The match will -+normally be an exact username or x509 distinguished name, but can -+optionally include wildcard globs. eg @code{*\@EXAMPLE.COM} to allow -+all users in the @code{EXAMPLE.COM} kerberos realm. The match will -+normally be appended to the end of the ACL, but can be inserted -+earlier in the list if the optional @code{index} parameter is supplied. -+@item acl deny [] -+add a match to the access control list, denying access. The match will -+normally be an exact username or x509 distinguished name, but can -+optionally include wildcard globs. eg @code{*\@EXAMPLE.COM} to allow -+all users in the @code{EXAMPLE.COM} kerberos realm. The match will -+normally be appended to the end of the ACL, but can be inserted -+earlier in the list if the optional @code{index} parameter is supplied. -+@item acl remove -+remove the specified match rule from the access control list. -+@item acl reset -+remove all matches from the access control list, and set the default -+policy back to @code{deny}. -+@end table -+ - @item screendump @var{filename} - Save screen into PPM image @var{filename}. - -Index: qemu-kvm-0.10/qemu/vnc-auth-sasl.c -=================================================================== ---- qemu-kvm-0.10.orig/qemu/vnc-auth-sasl.c -+++ qemu-kvm-0.10/qemu/vnc-auth-sasl.c -@@ -120,22 +120,32 @@ static int vnc_auth_sasl_check_access(Vn - { - const void *val; - int err; -+ int allow; - - err = sasl_getprop(vs->sasl.conn, SASL_USERNAME, &val); - if (err != SASL_OK) { -- VNC_DEBUG("cannot query SASL username on connection %d (%s)\n", -+ VNC_DEBUG("cannot query SASL username on connection %d (%s), denying access\n", - err, sasl_errstring(err, NULL, NULL)); - return -1; - } - if (val == NULL) { -- VNC_DEBUG("no client username was found\n"); -+ VNC_DEBUG("no client username was found, denying access\n"); - return -1; - } - VNC_DEBUG("SASL client username %s\n", (const char *)val); - - vs->sasl.username = qemu_strdup((const char*)val); - -- return 0; -+ if (vs->vd->sasl.acl == NULL) { -+ VNC_DEBUG("no ACL activated, allowing access\n"); -+ return 0; -+ } -+ -+ allow = qemu_acl_party_is_allowed(vs->vd->sasl.acl, vs->sasl.username); -+ -+ VNC_DEBUG("SASL client %s %s by ACL\n", vs->sasl.username, -+ allow ? "allowed" : "denied"); -+ return allow ? 0 : -1; - } - - static int vnc_auth_sasl_check_ssf(VncState *vs) -Index: qemu-kvm-0.10/qemu/vnc-auth-sasl.h -=================================================================== ---- qemu-kvm-0.10.orig/qemu/vnc-auth-sasl.h -+++ qemu-kvm-0.10/qemu/vnc-auth-sasl.h -@@ -30,6 +30,9 @@ - #include - - typedef struct VncStateSASL VncStateSASL; -+typedef struct VncDisplaySASL VncDisplaySASL; -+ -+#include "acl.h" - - struct VncStateSASL { - sasl_conn_t *conn; -@@ -56,6 +59,10 @@ struct VncStateSASL { - char *mechlist; - }; - -+struct VncDisplaySASL { -+ qemu_acl *acl; -+}; -+ - void vnc_sasl_client_cleanup(VncState *vs); - - long vnc_client_read_sasl(VncState *vs); -Index: qemu-kvm-0.10/qemu/vnc-tls.c -=================================================================== ---- qemu-kvm-0.10.orig/qemu/vnc-tls.c -+++ qemu-kvm-0.10/qemu/vnc-tls.c -@@ -255,6 +255,25 @@ int vnc_tls_validate_certificate(struct - gnutls_strerror (ret)); - return -1; - } -+ -+ if (vs->vd->tls.x509verify) { -+ int allow; -+ if (!vs->vd->tls.acl) { -+ VNC_DEBUG("no ACL activated, allowing access"); -+ gnutls_x509_crt_deinit (cert); -+ continue; -+ } -+ -+ allow = qemu_acl_party_is_allowed(vs->vd->tls.acl, -+ vs->tls.dname); -+ -+ VNC_DEBUG("TLS x509 ACL check for %s is %s\n", -+ vs->tls.dname, allow ? "allowed" : "denied"); -+ if (!allow) { -+ gnutls_x509_crt_deinit (cert); -+ return -1; -+ } -+ } - } - - gnutls_x509_crt_deinit (cert); -Index: qemu-kvm-0.10/qemu/vnc-tls.h -=================================================================== ---- qemu-kvm-0.10.orig/qemu/vnc-tls.h -+++ qemu-kvm-0.10/qemu/vnc-tls.h -@@ -31,6 +31,8 @@ - #include - #include - -+#include "acl.h" -+ - enum { - VNC_WIREMODE_CLEAR, - VNC_WIREMODE_TLS, -@@ -42,6 +44,7 @@ typedef struct VncStateTLS VncStateTLS; - /* Server state */ - struct VncDisplayTLS { - int x509verify; /* Non-zero if server requests & validates client cert */ -+ qemu_acl *acl; - - /* Paths to x509 certs/keys */ - char *x509cacert; -Index: qemu-kvm-0.10/qemu/vnc.c -=================================================================== ---- qemu-kvm-0.10.orig/qemu/vnc.c -+++ qemu-kvm-0.10/qemu/vnc.c -@@ -28,6 +28,7 @@ - #include "sysemu.h" - #include "qemu_socket.h" - #include "qemu-timer.h" -+#include "acl.h" - - #define VNC_REFRESH_INTERVAL (1000 / 30) - -@@ -2082,6 +2083,7 @@ int vnc_display_open(DisplayState *ds, c - int sasl = 0; - int saslErr; - #endif -+ int acl = 0; - - if (!vnc_display) - return -1; -@@ -2138,9 +2140,28 @@ int vnc_display_open(DisplayState *ds, c - return -1; - } - #endif -+ } else if (strncmp(options, "acl", 3) == 0) { -+ acl = 1; - } - } - -+#ifdef CONFIG_VNC_TLS -+ if (acl && x509 && vs->tls.x509verify) { -+ if (!(vs->tls.acl = qemu_acl_init("vnc.x509dname"))) { -+ fprintf(stderr, "Failed to create x509 dname ACL\n"); -+ exit(1); -+ } -+ } -+#endif -+#ifdef CONFIG_VNC_SASL -+ if (acl && sasl) { -+ if (!(vs->sasl.acl = qemu_acl_init("vnc.username"))) { -+ fprintf(stderr, "Failed to create username ACL\n"); -+ exit(1); -+ } -+ } -+#endif -+ - /* - * Combinations we support here: - * -Index: qemu-kvm-0.10/qemu/vnc.h -=================================================================== ---- qemu-kvm-0.10.orig/qemu/vnc.h -+++ qemu-kvm-0.10/qemu/vnc.h -@@ -98,6 +98,9 @@ struct VncDisplay - int subauth; /* Used by VeNCrypt */ - VncDisplayTLS tls; - #endif -+#ifdef CONFIG_VNC_SASL -+ VncDisplaySASL sasl; -+#endif - }; - - struct VncState diff --git a/make-release b/make-release deleted file mode 100755 index ec4bb42..0000000 --- a/make-release +++ /dev/null @@ -1,64 +0,0 @@ -#!/bin/bash -e - -# Based on avi's scripts/make-release from kvm-userspace.git - -usage() -{ - echo "usage: make-release name kernel-dir kernel-commit user-dir user-commit" - exit 1 -} - -[ $# -eq 5 ] || usage - -name="$1" -kdir="$2" -kcommit="$3" -udir="$4" -ucommit="$5" -archs=(x86 ia64) - -release_dir=$(mktemp -d) - -tarball="$(pwd)/$name.tar.gz" - -cd "${release_dir}" -(cd "$udir"; git archive --format=tar --prefix="$name"/ "$ucommit") | tar x -cd "$name" -cat < SOURCES -kernel: $(cd "$kdir"; git rev-parse "$kcommit") -userspace: $(cd "$udir"; git rev-parse "$ucommit") -EOF - -paths=(drivers/kvm virt/kvm) -files=(kvm.h kvm_host.h kvm_para.h kvm_types.h kvm_x86_emulate.h virtext.h svm.h vmx.h) -for file in "${files[@]}"; do - for arch in "${archs[@]}"; do - for variant in include/asm-"$arch" arch/"$arch"/include/asm; do - paths+=("$variant"/"$file") - done - done - paths+=(include/linux/"$file") -done -for arch in "${archs[@]}"; do - paths+=(arch/"$arch"/kvm) -done - -(cd "$kdir"; git archive --format=tar --prefix=linux/ "$kcommit" "${paths[@]}") | tar x - -touch kernel/config.kbuild -echo ARCH=ia64 > config.mak -make -C kernel sync LINUX=../linux version="$name" >/dev/null -echo ARCH=x86_64 > config.mak -make -C kernel sync LINUX=../linux version="$name" >/dev/null -rm -rf config.mak linux kernel/config.kbuild -#rm -rf kernel/include/asm kernel/include-compat/asm -sed -i "s/kvm-devel/$name/" qemu/configure - -cd .. - -tar czf "$tarball" "$name" - -cd $(dirname "$tarball") -md5sum $(basename "$tarball") - -rm -rf "${release_dir}" diff --git a/qemu-disable-preadv.patch b/qemu-disable-preadv.patch new file mode 100644 index 0000000..dae289d --- /dev/null +++ b/qemu-disable-preadv.patch @@ -0,0 +1,16 @@ +diff -up qemu-kvm-devel-85/qemu/configure.disable-preadv qemu-kvm-devel-85/qemu/configure +--- qemu-kvm-devel-85/qemu/configure.disable-preadv 2009-04-27 16:09:05.000000000 +0100 ++++ qemu-kvm-devel-85/qemu/configure 2009-04-27 16:09:36.000000000 +0100 +@@ -1189,9 +1189,9 @@ cat > $TMPC < /dev/null 2> /dev/null ; then +- preadv=yes +-fi ++#if $cc $ARCH_CFLAGS -o $TMPE $TMPC > /dev/null 2> /dev/null ; then ++# preadv=yes ++#fi + + ########################################## + # fdt probe diff --git a/qemu-fix-arm-framebuffer-build.patch b/qemu-fix-arm-framebuffer-build.patch new file mode 100644 index 0000000..8a45bd8 --- /dev/null +++ b/qemu-fix-arm-framebuffer-build.patch @@ -0,0 +1,45 @@ +From: Mark McLoughlin +Date: Mon, 27 Apr 2009 10:18:14 +0100 +Subject: [PATCH] kvm: qemu: framebuffer: build fix for target-arm + +Include qemu-kvm.h for non-KVM_UPSTREAM building and surround the +kvm code with USE_KVM guards. + +Fixes target-arm: + + qemu/hw/framebuffer.c: In function 'framebuffer_update_display': + qemu/hw/framebuffer.c:53: warning: implicit declaration of function 'kvm_enabled' + qemu/hw/framebuffer.c:54: warning: implicit declaration of function 'kvm_physical_sync_dirty_bitmap' + +Signed-off-by: Mark McLoughlin +--- + qemu/hw/framebuffer.c | 3 +++ + 1 files changed, 3 insertions(+), 0 deletions(-) + +diff --git a/qemu/hw/framebuffer.c b/qemu/hw/framebuffer.c +index 1086ba9..e2d7604 100644 +--- a/qemu/hw/framebuffer.c ++++ b/qemu/hw/framebuffer.c +@@ -18,6 +18,7 @@ + #include "console.h" + #include "framebuffer.h" + #include "kvm.h" ++#include "qemu-kvm.h" + + /* Render an image from a shared memory framebuffer. */ + +@@ -50,9 +51,11 @@ void framebuffer_update_display( + *first_row = -1; + src_len = src_width * rows; + ++#ifdef USE_KVM + if (kvm_enabled()) { + kvm_physical_sync_dirty_bitmap(base, src_len); + } ++#endif + pd = cpu_get_physical_page_desc(base); + pd2 = cpu_get_physical_page_desc(base + src_len - 1); + /* We should reall check that this is a continuous ram region. +-- +1.6.0.6 + diff --git a/qemu-fix-debuginfo.patch b/qemu-fix-debuginfo.patch deleted file mode 100644 index f6f1d71..0000000 --- a/qemu-fix-debuginfo.patch +++ /dev/null @@ -1,85 +0,0 @@ -From: Riku Voipio -Subject: [Qemu-devel] [PATCH] Make binary stripping conditional - -Currently qemu unconditionally strips binaries on install. This -is a problem for packagers who may want to store/ship debug symbols -of compiled packages for debugging purposes. - -Keep stripping as default for the oldtimers and add a ---disable-strip flag to override. - -Signed-off-by: Riku Voipio ---- - Makefile | 2 +- - Makefile.target | 2 +- - configure | 9 ++++++++- - 3 files changed, 10 insertions(+), 3 deletions(-) - -Index: qemu-kvm-0.10/qemu/Makefile -=================================================================== ---- qemu-kvm-0.10.orig/qemu/Makefile -+++ qemu-kvm-0.10/qemu/Makefile -@@ -256,7 +256,7 @@ endif - install: all $(if $(BUILD_DOCS),install-doc) - mkdir -p "$(DESTDIR)$(bindir)" - ifneq ($(TOOLS),) -- $(INSTALL) -m 755 -s $(TOOLS) "$(DESTDIR)$(bindir)" -+ $(INSTALL) -m 755 $(STRIP_OPT) $(TOOLS) "$(DESTDIR)$(bindir)" - endif - ifneq ($(BLOBS),) - mkdir -p "$(DESTDIR)$(datadir)" -Index: qemu-kvm-0.10/qemu/configure -=================================================================== ---- qemu-kvm-0.10.orig/qemu/configure -+++ qemu-kvm-0.10/qemu/configure -@@ -154,6 +154,7 @@ case "$cpu" in - esac - gprof="no" - sparse="no" -+strip_opt="yes" - bigendian="no" - mingw32="no" - EXESUF="" -@@ -403,6 +404,8 @@ for opt do - ;; - --disable-sparse) sparse="no" - ;; -+ --disable-strip) strip_opt="no" -+ ;; - --disable-vnc-tls) vnc_tls="no" - ;; - --disable-vnc-sasl) vnc_sasl="no" -@@ -556,6 +559,7 @@ echo " --install=INSTALL use spe - echo " --static enable static build [$static]" - echo " --enable-sparse enable sparse checker" - echo " --disable-sparse disable sparse checker (default)" -+echo " --disable-strip disable stripping binaries" - echo " --disable-werror disable compilation abort on warning" - echo " --disable-sdl disable SDL" - echo " --enable-cocoa enable COCOA (Mac OS X only)" -@@ -1242,6 +1246,7 @@ echo "host big endian $bigendian" - echo "target list $target_list" - echo "gprof enabled $gprof" - echo "sparse enabled $sparse" -+echo "strip binaries $strip_opt" - echo "profiler $profiler" - echo "static build $static" - echo "-Werror enabled $werror" -@@ -1318,7 +1323,6 @@ echo "INSTALL=$install" >> $config_mak - echo "CC=$cc" >> $config_mak - echo "HOST_CC=$host_cc" >> $config_mak - echo "AR=$ar" >> $config_mak --echo "STRIP=$strip -s -R .comment -R .note" >> $config_mak - # XXX: only use CFLAGS and LDFLAGS ? - # XXX: should export HOST_CFLAGS and HOST_LDFLAGS for cross - # compilation of dyngen tool (useful for win32 build on Linux host) -@@ -1405,6 +1409,9 @@ if test "$sparse" = "yes" ; then - echo "HOST_CC := REAL_CC=\"\$(HOST_CC)\" cgcc" >> $config_mak - echo "CFLAGS += -Wbitwise -Wno-transparent-union -Wno-old-initializer -Wno-non-pointer-null" >> $config_mak - fi -+if test "$strip_opt" = "yes" ; then -+ echo "STRIP_OPT=-s" >> $config_mak -+fi - if test "$bigendian" = "yes" ; then - echo "WORDS_BIGENDIAN=yes" >> $config_mak - echo "#define WORDS_BIGENDIAN 1" >> $config_h diff --git a/qemu-fix-display-breakage.patch b/qemu-fix-display-breakage.patch deleted file mode 100644 index 8645bc2..0000000 --- a/qemu-fix-display-breakage.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 9d1b494a2d5dd2c129994edcf4eb7630bb554964 Mon Sep 17 00:00:00 2001 -From: aliguori -Date: Tue, 7 Apr 2009 20:55:58 +0000 -Subject: [PATCH 1/1] Fix crash on resolution change -> screen dump -> vga redraw (Avi Kivity) - -The vga screen dump function updates last_width and last_height, -but does not change the DisplaySurface that these variables describe. -A consequent vga_draw_graphic() will therefore fail to resize the -surface and crash. - -Fix by invalidating the display state after a screen dump, forcing -vga_draw_graphic() to reallocate the DisplaySurface. - -Signed-off-by: Avi Kivity -Signed-off-by: Anthony Liguori - - -git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@7026 c046a42c-6fe2-441c-8c8c-71466251a162 ---- - qemu/hw/vga.c | 1 + - 1 files changed, 1 insertions(+), 0 deletions(-) - -diff --git a/qemu/hw/vga.c b/qemu/hw/vga.c -index b1e4373..4d1049b 100644 ---- a/qemu/hw/vga.c -+++ b/qemu/hw/vga.c -@@ -2678,4 +2678,5 @@ static void vga_screen_dump(void *opaque, const char *filename) - vga_screen_dump_graphic(s, filename); - else - vga_screen_dump_text(s, filename); -+ vga_invalidate_display(s); - } --- -1.6.0.6 - diff --git a/qemu-fix-gcc.patch b/qemu-fix-gcc.patch deleted file mode 100644 index e21a877..0000000 --- a/qemu-fix-gcc.patch +++ /dev/null @@ -1,79 +0,0 @@ -From 2ced1d80f01645885ac2e28107f724886eb1cd5a Mon Sep 17 00:00:00 2001 -From: Jochen Roth -Date: Thu, 12 Mar 2009 14:19:19 +0100 -Subject: [PATCH] kvm: testsuite: compile fix - avoid raw string literal - -This patch fixes compilation problems of kvm-userspace on current gcc -4.4 compilers which implement the following standard: -http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2442.htm - -Signed-off-by: Jochen Roth -Signed-off-by: Avi Kivity ---- - user/test/x86/apic.c | 32 ++++++++++++++++---------------- - user/test/x86/vmexit.c | 2 +- - 2 files changed, 17 insertions(+), 17 deletions(-) - -Index: qemu-kvm-0.10/user/test/x86/apic.c -=================================================================== ---- qemu-kvm-0.10.orig/user/test/x86/apic.c -+++ qemu-kvm-0.10/user/test/x86/apic.c -@@ -54,14 +54,14 @@ asm ( - "push %r9 \n\t" - "push %r8 \n\t" - #endif -- "push %"R"di \n\t" -- "push %"R"si \n\t" -- "push %"R"bp \n\t" -- "push %"R"sp \n\t" -- "push %"R"bx \n\t" -- "push %"R"dx \n\t" -- "push %"R"cx \n\t" -- "push %"R"ax \n\t" -+ "push %"R "di \n\t" -+ "push %"R "si \n\t" -+ "push %"R "bp \n\t" -+ "push %"R "sp \n\t" -+ "push %"R "bx \n\t" -+ "push %"R "dx \n\t" -+ "push %"R "cx \n\t" -+ "push %"R "ax \n\t" - #ifdef __x86_64__ - "mov %rsp, %rdi \n\t" - "callq *8*16(%rsp) \n\t" -@@ -70,14 +70,14 @@ asm ( - "calll *4+4*8(%esp) \n\t" - "add $4, %esp \n\t" - #endif -- "pop %"R"ax \n\t" -- "pop %"R"cx \n\t" -- "pop %"R"dx \n\t" -- "pop %"R"bx \n\t" -- "pop %"R"bp \n\t" -- "pop %"R"bp \n\t" -- "pop %"R"si \n\t" -- "pop %"R"di \n\t" -+ "pop %"R "ax \n\t" -+ "pop %"R "cx \n\t" -+ "pop %"R "dx \n\t" -+ "pop %"R "bx \n\t" -+ "pop %"R "bp \n\t" -+ "pop %"R "bp \n\t" -+ "pop %"R "si \n\t" -+ "pop %"R "di \n\t" - #ifdef __x86_64__ - "pop %r8 \n\t" - "pop %r9 \n\t" -Index: qemu-kvm-0.10/user/test/x86/vmexit.c -=================================================================== ---- qemu-kvm-0.10.orig/user/test/x86/vmexit.c -+++ qemu-kvm-0.10/user/test/x86/vmexit.c -@@ -31,7 +31,7 @@ int main() - - t1 = rdtsc(); - for (i = 0; i < N; ++i) -- asm volatile ("push %%"R"bx; cpuid; pop %%"R"bx" -+ asm volatile ("push %%"R "bx; cpuid; pop %%"R "bx" - : : : "eax", "ecx", "edx"); - t2 = rdtsc(); - printf("vmexit latency: %d\n", (int)((t2 - t1) / N)); diff --git a/qemu-fix-qcow2-2TB.patch b/qemu-fix-qcow2-2TB.patch deleted file mode 100644 index 4fee796..0000000 --- a/qemu-fix-qcow2-2TB.patch +++ /dev/null @@ -1,77 +0,0 @@ -From 2d2431f03fc78b532f3a1c5f858cf78859d50fc3 Mon Sep 17 00:00:00 2001 -From: aliguori -Date: Sun, 5 Apr 2009 17:40:58 +0000 -Subject: [PATCH] qcow2: fix image creation for large, > ~2TB, images (Chris Wright) - -When creating large disk images w/ qcow2 format, qcow2_create is hard -coded to creating a single refcount block. This is insufficient for -large images, and will cause qemu-img to segfault as it walks off the -end of the refcount block. Keep track of the space needed during image -create and create proper number of refcount blocks accordingly. - -https://bugzilla.redhat.com/show_bug.cgi?id=491943 - -Signed-off-by: Chris Wright -Signed-off-by: Anthony Liguori - - -git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6982 c046a42c-6fe2-441c-8c8c-71466251a162 ---- - block-qcow2.c | 20 +++++++++++++------- - 1 files changed, 13 insertions(+), 7 deletions(-) - -Index: qemu-kvm-0.10/qemu/block-qcow2.c -=================================================================== ---- qemu-kvm-0.10.orig/qemu/block-qcow2.c -+++ qemu-kvm-0.10/qemu/block-qcow2.c -@@ -1458,6 +1458,7 @@ static int qcow_create(const char *filen - const char *backing_file, int flags) - { - int fd, header_size, backing_filename_len, l1_size, i, shift, l2_bits; -+ int ref_clusters = 0; - QCowHeader header; - uint64_t tmp, offset; - QCowCreateState s1, *s = &s1; -@@ -1498,22 +1499,28 @@ static int qcow_create(const char *filen - offset += align_offset(l1_size * sizeof(uint64_t), s->cluster_size); - - s->refcount_table = qemu_mallocz(s->cluster_size); -- s->refcount_block = qemu_mallocz(s->cluster_size); - - s->refcount_table_offset = offset; - header.refcount_table_offset = cpu_to_be64(offset); - header.refcount_table_clusters = cpu_to_be32(1); - offset += s->cluster_size; -- -- s->refcount_table[0] = cpu_to_be64(offset); - s->refcount_block_offset = offset; -- offset += s->cluster_size; -+ -+ /* count how many refcount blocks needed */ -+ tmp = offset >> s->cluster_bits; -+ ref_clusters = (tmp >> (s->cluster_bits - REFCOUNT_SHIFT)) + 1; -+ for (i=0; i < ref_clusters; i++) { -+ s->refcount_table[i] = cpu_to_be64(offset); -+ offset += s->cluster_size; -+ } -+ -+ s->refcount_block = qemu_mallocz(ref_clusters * s->cluster_size); - - /* update refcounts */ - create_refcount_update(s, 0, header_size); - create_refcount_update(s, s->l1_table_offset, l1_size * sizeof(uint64_t)); - create_refcount_update(s, s->refcount_table_offset, s->cluster_size); -- create_refcount_update(s, s->refcount_block_offset, s->cluster_size); -+ create_refcount_update(s, s->refcount_block_offset, ref_clusters * s->cluster_size); - - /* write all the data */ - write(fd, &header, sizeof(header)); -@@ -1529,7 +1536,7 @@ static int qcow_create(const char *filen - write(fd, s->refcount_table, s->cluster_size); - - lseek(fd, s->refcount_block_offset, SEEK_SET); -- write(fd, s->refcount_block, s->cluster_size); -+ write(fd, s->refcount_block, ref_clusters * s->cluster_size); - - qemu_free(s->refcount_table); - qemu_free(s->refcount_block); diff --git a/qemu-fix-qcow2-corruption.patch b/qemu-fix-qcow2-corruption.patch index dfed7be..53ac9ec 100644 --- a/qemu-fix-qcow2-corruption.patch +++ b/qemu-fix-qcow2-corruption.patch @@ -1,26 +1,3 @@ -From: Nolan Leake sigbus.net> -Subject: [PATCH] Fix (at least one cause of) qcow2 corruption. - -qcow2's get_cluster_offset() scans forward in the l2 table to find other -clusters that have the same allocation status as the first cluster. -This is used by (among others) qcow_is_allocated(). - -Unfortunately, it was not checking to be sure that it didn't fall off -the end of the l2 table. This patch adds that check. - -The symptom that motivated me to look into this was that -bdrv_is_allocated() was returning false when there was in fact data -there. This is one of many ways this bug could lead to data corruption. - -I checked the other place that scans for consecutive unallocated blocks -(alloc_cluster_offset()) and it appears to be OK: - nb_clusters = MIN(nb_clusters, s->l2_size - l2_index); -appears to prevent the same problem from occurring. - -Signed-off-by: Nolan Leake sigbus.net> - ---- - From: Kevin Wolf Subject: [PATCH] qcow2 corruption: Fix alloc_cluster_link_l2 @@ -41,22 +18,10 @@ qcow2 image (the header is gone after three loop iterations): Signed-off-by: Kevin Wolf -diff -up qemu-kvm-0.10/qemu/block-qcow2.c.qcow2-corruption qemu-kvm-0.10/qemu/block-qcow2.c -diff -up qemu-kvm-0.10/qemu/block-qcow2.c.qcow2-corruption qemu-kvm-0.10/qemu/block-qcow2.c ---- qemu-kvm-0.10/qemu/block-qcow2.c.qcow2-corruption 2009-04-21 09:57:21.000000000 +0100 -+++ qemu-kvm-0.10/qemu/block-qcow2.c 2009-04-21 09:58:27.000000000 +0100 -@@ -670,6 +670,10 @@ static uint64_t get_cluster_offset(Block - - nb_available = (nb_available >> 9) + index_in_cluster; - -+ if (nb_needed > nb_available) { -+ nb_needed = nb_available; -+ } -+ - cluster_offset = 0; - - /* seek the the l2 offset in the l1 table */ -@@ -912,7 +916,7 @@ static int alloc_cluster_link_l2(BlockDr +diff -up qemu-kvm-devel-85/qemu/block-qcow2.c.qcow2-corruption qemu-kvm-devel-85/qemu/block-qcow2.c +--- qemu-kvm-devel-85/qemu/block-qcow2.c.qcow2-corruption 2009-04-21 10:57:31.000000000 +0100 ++++ qemu-kvm-devel-85/qemu/block-qcow2.c 2009-04-24 19:29:44.000000000 +0100 +@@ -1007,7 +1007,7 @@ static int alloc_cluster_link_l2(BlockDr goto err; for (i = 0; i < j; i++) diff --git a/qemu-roms-more-room.patch b/qemu-roms-more-room.patch deleted file mode 100644 index 9437e8d..0000000 --- a/qemu-roms-more-room.patch +++ /dev/null @@ -1,132 +0,0 @@ -From 34b39c2ba6cc08239a707b52bfb2886df2aa8dec Mon Sep 17 00:00:00 2001 -From: aliguori -Date: Sat, 28 Mar 2009 17:28:45 +0000 -Subject: [PATCH] get roms more room. (Glauber Costa) - -This patch increases by 50 % the size available for option roms. -The main motivator is that some roms grew bigger than the 64k we -currently allocate for them (Hey, it's 2009!) - -One example is the gpxe project, that produces some roms with 69k, -70k, etc. The space proposed by this patch actually makes it as -big as 84k. Probably still a fit for some time. - -But there is no free lunch. This space must come from somewhere, -and we take it from vga rom space. Currently, our vga roms are -around 35k in size. With this patch, option rom space will begin -just after vga ends, aligned to the next 2k boundary. - -Technicaly, we could do the same with the uper space (the bios itself), -but since bochs bios is already 128 k in size, I don't see an -urgent need to do it. - -[ fix case for vgabioses smaller than 30k, by Carl-Daniel Hailfinger ] - -Signed-off-by: Glauber Costa -Signed-off-by: Anthony Liguori - - -git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6896 c046a42c-6fe2-441c-8c8c-71466251a162 ---- - hw/pc.c | 29 +++++++++++++++++++---------- - 1 files changed, 19 insertions(+), 10 deletions(-) - -Index: qemu-kvm-0.10/qemu/hw/pc.c -=================================================================== ---- qemu-kvm-0.10.orig/qemu/hw/pc.c -+++ qemu-kvm-0.10/qemu/hw/pc.c -@@ -813,7 +813,7 @@ static void pc_init1(ram_addr_t ram_size - { - char buf[1024]; - int ret, linux_boot, i; -- ram_addr_t ram_addr, vga_ram_addr, bios_offset, vga_bios_offset; -+ ram_addr_t ram_addr, vga_ram_addr, bios_offset, vga_bios_offset, option_rom_start = 0; - ram_addr_t below_4g_mem_size, above_4g_mem_size = 0; - int bios_size, isa_bios_size, vga_bios_size; - int pci_option_rom_offset; -@@ -825,6 +825,7 @@ static void pc_init1(ram_addr_t ram_size - int index; - BlockDriverState *hd[MAX_IDE_BUS * MAX_IDE_DEVS]; - BlockDriverState *fd[MAX_FD]; -+ int using_vga = cirrus_vga_enabled || std_vga_enabled || vmsvga_enabled; - - if (ram_size >= 0xe0000000 ) { - above_4g_mem_size = ram_size - 0xe0000000; -@@ -900,7 +901,7 @@ static void pc_init1(ram_addr_t ram_size - exit(1); - } - -- if (cirrus_vga_enabled || std_vga_enabled || vmsvga_enabled) { -+ if (using_vga) { - /* VGA BIOS load */ - if (cirrus_vga_enabled) { - snprintf(buf, sizeof(buf), "%s/%s", bios_dir, VGABIOS_CIRRUS_FILENAME); -@@ -918,12 +919,21 @@ vga_bios_error: - fprintf(stderr, "qemu: could not load VGA BIOS '%s'\n", buf); - exit(1); - } -+ /* Round up vga bios size to the next 2k boundary */ -+ vga_bios_size = (vga_bios_size + 2047) & ~2047; -+ option_rom_start = 0xc0000 + vga_bios_size; - - /* setup basic memory access */ -- cpu_register_physical_memory(0xc0000, 0x10000, -+ cpu_register_physical_memory(0xc0000, vga_bios_size, - vga_bios_offset | IO_MEM_ROM); - } - -+ /* No point in placing option roms before this address, since bochs bios -+ * will only start looking for it at 0xc8000 */ -+ if (option_rom_start < 0xc8000) -+ option_rom_start = 0xc8000; -+ -+ - /* map the last 128KB of the BIOS in ISA space */ - isa_bios_size = bios_size; - if (isa_bios_size > (128 * 1024)) -@@ -944,14 +954,14 @@ vga_bios_error: - ram_addr_t option_rom_offset; - int size, offset; - -- offset = 0; -+ offset = option_rom_start; - if (linux_boot) { - option_rom_offset = qemu_ram_alloc(TARGET_PAGE_SIZE); - load_linux(phys_ram_base + option_rom_offset, - kernel_filename, initrd_filename, kernel_cmdline); -- cpu_register_physical_memory(0xd0000, TARGET_PAGE_SIZE, -+ cpu_register_physical_memory(option_rom_start, TARGET_PAGE_SIZE, - option_rom_offset | IO_MEM_ROM); -- offset = TARGET_PAGE_SIZE; -+ offset += TARGET_PAGE_SIZE; - } - - for (i = 0; i < nb_option_roms; i++) { -@@ -961,13 +971,13 @@ vga_bios_error: - option_rom[i]); - exit(1); - } -- if (size > (0x10000 - offset)) -+ if (size > (0xe0000 - offset)) - goto option_rom_error; - option_rom_offset = qemu_ram_alloc(size); - ret = load_image(option_rom[i], phys_ram_base + option_rom_offset); - if (ret != size) { - option_rom_error: -- fprintf(stderr, "Too many option ROMS\n"); -+ fprintf(stderr, "Could not fit %soption roms in available space\n", using_vga ? "VGA bios and " : ""); - exit(1); - } - size = (size + 4095) & ~4095; -@@ -975,9 +985,8 @@ vga_bios_error: - initialization, and (optionally) marked readonly by the BIOS - before INT 19h. See the PNPBIOS specification, appendix B. - DDIM support is mandatory for proper PCI expansion ROM support. */ -- cpu_register_physical_memory(0xd0000 + offset, -- size, option_rom_offset /* | IO_MEM_ROM */); -- option_rom_setup_reset(0xd0000 + offset, size); -+ cpu_register_physical_memory(offset, size, option_rom_offset /* | IO_MEM_ROM */); -+ option_rom_setup_reset(offset, size); - offset += size; - } - pci_option_rom_offset = offset; diff --git a/qemu-virtio-blk-boot-on.patch b/qemu-virtio-blk-boot-on.patch new file mode 100644 index 0000000..4d2ba6a --- /dev/null +++ b/qemu-virtio-blk-boot-on.patch @@ -0,0 +1,32 @@ +From: Pauline Middelink +To: kvm@vger.kernel.org +Subject: kvm-85 won't boot guests with virtio block device + +Hi, + +To follow up on the issues with kvm-85 and libvirt I discovered the following +issue: libvirt detects from the help of qemu which options it can give to +qemu. (in this case obviously /usr/kvm/bin/qemu-system-x86_64 -help) + +If you look carefully to the output of the -help of qemu from kvm-84 and +kvm-85, you will notice the boot flag to the -drive option has disappeared! +Hence letting libvirt believe it isnt allowed to use it, hence the unable +to boot error. + +A small patch which fixes the problem for me, is attached. + + Met vriendelijke groet, + Pauline Middelink + +diff -ur kvm-85/qemu/qemu-options.hx kvm-85a/qemu/qemu-options.hx +--- kvm-85/qemu/qemu-options.hx 2009-04-21 11:57:31.000000000 +0200 ++++ kvm-85a/qemu/qemu-options.hx 2009-04-24 19:04:50.000000000 +0200 +@@ -77,6 +77,7 @@ + "-drive [file=file][,if=type][,bus=n][,unit=m][,media=d][,index=i]\n" + " [,cyls=c,heads=h,secs=s[,trans=t]][,snapshot=on|off]\n" + " [,cache=writethrough|writeback|none][,format=f][,serial=s]\n" ++ " [,boot=on|off]\n" + " use 'file' as a drive image\n") + STEXI + @item -drive @var{option}[,@var{option}[,@var{option}[,...]]] + diff --git a/qemu.spec b/qemu.spec index 254143c..4790d19 100644 --- a/qemu.spec +++ b/qemu.spec @@ -1,42 +1,41 @@ +%define kvmvernum 85 +%define kvmvertag kvm%{kvmvernum} +%define kvmverfull kvm-devel-%{kvmvernum} + Summary: QEMU is a FAST! processor emulator Name: qemu -Version: 0.10 -Release: 15%{?dist} -# I have mistakenly thought the revision name would be 1.0. -# So 0.10 series get Epoch = 1 +Version: 0.10.50 +Release: 1.%{kvmvertag}%{?dist} +# Epoch because we pushed a qemu-1.0 package Epoch: 2 License: GPLv2+ and LGPLv2+ and BSD Group: Development/Tools URL: http://www.qemu.org/ -# To re-create the tarball below: -# $> git clone git://git.kernel.org/pub/scm/linux/kernel/git/avi/kvm.git -# $> git clone git://git.kernel.org/pub/scm/linux/kernel/git/avi/kvm-userspace.git -# $> make-release qemu-kvm-%{version}.tar.gz $(pwd)/kvm v2.6.29-6998-g1d0cdf1 \ -# $(pwd)/kvm-userspace kvm-84-196-ga01bd3f -Source0: qemu-kvm-%{version}.tar.gz -Source1: make-release -Source2: qemu.init -Source3: kvm.modules - -Patch1: 01-tls-handshake-fix.patch -Patch2: 02-vnc-monitor-info.patch -Patch3: 03-display-keymaps.patch -Patch4: 04-vnc-struct.patch -Patch5: 05-vnc-tls-vencrypt.patch -Patch6: 06-vnc-sasl.patch -Patch7: 07-vnc-monitor-authinfo.patch -Patch8: 08-vnc-acl-mgmt.patch - -Patch9: kvm-upstream-ppc.patch -Patch10: qemu-fix-debuginfo.patch -Patch11: qemu-fix-gcc.patch -Patch12: qemu-roms-more-room.patch -Patch13: qemu-roms-more-room-fix-vga-align.patch -Patch14: qemu-bios-bigger-roms.patch -Patch15: qemu-fix-display-breakage.patch -Patch16: qemu-fix-qcow2-2TB.patch -Patch17: qemu-fix-qcow2-corruption.patch +Source0: http://download.sourceforge.net/sourceforge/kvm/qemu-%{kvmverfull}.tar.gz +Source1: qemu.init +Source2: kvm.modules + +# Hack until merge happens upstream +Patch01: kvm-upstream-ppc.patch + +# Not upstream, why? +Patch02: qemu-bios-bigger-roms.patch + +# Fixed upstream by f753ff1638 +Patch03: qemu-roms-more-room-fix-vga-align.patch + +# Fixed upstream by 641636d19e +Patch04: qemu-fix-qcow2-corruption.patch + +# Seen on kvm list +Patch05: qemu-virtio-blk-boot-on.patch + +# kvm-85 build fix, submitted upstream +Patch06: qemu-fix-arm-framebuffer-build.patch + +# Disable preadv()/pwritev() until bug #497429 is fixed +Patch07: qemu-disable-preadv.patch BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) BuildRequires: SDL-devel zlib-devel which texi2html gnutls-devel cyrus-sasl-devel @@ -206,25 +205,20 @@ such as kvmtrace and kvm_stat. %endif %prep -%setup -q -n qemu-kvm-%{version} - -%patch1 -p1 -%patch2 -p1 -%patch3 -p1 -%patch4 -p1 -%patch5 -p1 -%patch6 -p1 -%patch7 -p1 -%patch8 -p1 -%patch9 -p1 -%patch10 -p1 -%patch11 -p1 -%patch12 -p1 -%patch13 -p1 -%patch14 -p1 -%patch15 -p1 -%patch16 -p1 -%patch17 -p1 +%setup -q -n qemu-%{kvmverfull} + +# +# Hack - kvm-85 missing kernel/include/asm symlink +# +(cd kernel/include && ln -s asm-x86 asm) + +%patch01 -p1 -b .kvm-upstream-ppc +%patch02 -p1 -b .bios-bigger-roms +%patch03 -p1 -b .roms-more-room-fix-vga-align +%patch04 -p1 -b .fix-qcow2-corruption +%patch05 -p1 -b .virtio-blk-boot-on +%patch06 -p1 -b .framebuffer-build-fix +%patch07 -p1 -b .disable-preadv %build # systems like rhel build system does not have a recent enough linker so @@ -262,7 +256,6 @@ cp user/kvmtrace_format . make clean %endif -echo "%{name}-%{version}" > $(pwd)/kernel/.kernelrelease cd qemu ./configure \ --target-list="i386-softmmu x86_64-softmmu arm-softmmu cris-softmmu m68k-softmmu \ @@ -282,8 +275,7 @@ cd qemu --audio-drv-list=pa,sdl,alsa,oss \ --extra-cflags="$RPM_OPT_FLAGS" - -make %{?_smp_mflags} $buildldflags +make V=1 %{?_smp_mflags} $buildldflags %install rm -rf $RPM_BUILD_ROOT @@ -292,7 +284,7 @@ rm -rf $RPM_BUILD_ROOT mkdir -p $RPM_BUILD_ROOT/%{_sysconfdir}/sysconfig/modules mkdir -p $RPM_BUILD_ROOT%{_bindir}/ -install -m 0755 %{SOURCE3} $RPM_BUILD_ROOT/%{_sysconfdir}/sysconfig/modules/kvm.modules +install -m 0755 %{SOURCE2} $RPM_BUILD_ROOT/%{_sysconfdir}/sysconfig/modules/kvm.modules install -m 0755 kvmtrace $RPM_BUILD_ROOT%{_bindir}/ install -m 0755 kvmtrace_format $RPM_BUILD_ROOT%{_bindir}/ install -m 0755 kvm_stat $RPM_BUILD_ROOT%{_bindir}/ @@ -308,7 +300,7 @@ make prefix="${RPM_BUILD_ROOT}%{_prefix}" \ docdir="${RPM_BUILD_ROOT}%{_docdir}/%{name}-%{version}" \ datadir="${RPM_BUILD_ROOT}%{_prefix}/share/qemu" install chmod -x ${RPM_BUILD_ROOT}%{_mandir}/man1/* -install -D -p -m 0755 %{SOURCE2} $RPM_BUILD_ROOT%{_sysconfdir}/rc.d/init.d/qemu +install -D -p -m 0755 %{SOURCE1} $RPM_BUILD_ROOT%{_sysconfdir}/rc.d/init.d/qemu install -D -p -m 0644 -t ${RPM_BUILD_ROOT}/%{qemudocdir} Changelog README TODO COPYING COPYING.LIB LICENSE install -D -p -m 0644 qemu.sasl $RPM_BUILD_ROOT%{_sysconfdir}/sasl2/qemu.conf @@ -339,8 +331,6 @@ ln -s ../openbios/openbios-ppc %{buildroot}/%{_prefix}/share/qemu/openbios-ppc ln -s ../openbios/openbios-sparc32 %{buildroot}/%{_prefix}/share/qemu/openbios-sparc32 ln -s ../openbios/openbios-sparc64 %{buildroot}/%{_prefix}/share/qemu/openbios-sparc64 - - %clean rm -rf $RPM_BUILD_ROOT @@ -463,9 +453,22 @@ fi %files img %defattr(-,root,root) %{_bindir}/qemu-img +%{_bindir}/qemu-io %{_mandir}/man1/qemu-img.1* %changelog +* Mon Apr 27 2009 Mark McLoughlin - 2:0.10.50-1.kvm85 +- Update to qemu-kvm-devel-85 +- kvm-85 is based on qemu development branch, currently version 0.10.50 +- Include new qemu-io utility in qemu-img package +- Re-instate -help string for boot=on to fix virtio booting with libvirt +- Drop upstreamed patches +- Fix missing kernel/include/asm symlink in upstream tarball +- Fix target-arm build +- Disable preadv()/pwritev() until bug #497429 is fixed +- Kill more .kernelrelease uselessness +- Make non-kvm qemu build verbose + * Fri Apr 24 2009 Mark McLoughlin - 2:0.10-15 - Fix source numbering typos caused by make-release addition diff --git a/sources b/sources index 004ec2d..14a7621 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -04c32fb43c722f180654f53e04ad17dd qemu-kvm-0.10.tar.gz +3b671f64b66e7e6e571516193c184653 qemu-kvm-devel-85.tar.gz