|
1 /* |
|
2 * QEMU VNC display driver |
|
3 * |
|
4 * Copyright (C) 2006 Anthony Liguori <anthony@codemonkey.ws> |
|
5 * Copyright (C) 2006 Fabrice Bellard |
|
6 * |
|
7 * Permission is hereby granted, free of charge, to any person obtaining a copy |
|
8 * of this software and associated documentation files (the "Software"), to deal |
|
9 * in the Software without restriction, including without limitation the rights |
|
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|
11 * copies of the Software, and to permit persons to whom the Software is |
|
12 * furnished to do so, subject to the following conditions: |
|
13 * |
|
14 * The above copyright notice and this permission notice shall be included in |
|
15 * all copies or substantial portions of the Software. |
|
16 * |
|
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
|
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
|
23 * THE SOFTWARE. |
|
24 */ |
|
25 |
|
26 #include "qemu-common.h" |
|
27 #include "console.h" |
|
28 #include "sysemu.h" |
|
29 #include "qemu_socket.h" |
|
30 #include "qemu-timer.h" |
|
31 #include "gui_host.h" |
|
32 #include "audio/audio.h" |
|
33 |
|
34 #define VNC_REFRESH_INTERVAL (1000 / 30) |
|
35 |
|
36 #include "vnc_keysym.h" |
|
37 #include "keymaps.c" |
|
38 #include "d3des.h" |
|
39 |
|
40 #ifdef CONFIG_VNC_TLS |
|
41 #include <gnutls/gnutls.h> |
|
42 #include <gnutls/x509.h> |
|
43 #endif /* CONFIG_VNC_TLS */ |
|
44 |
|
45 // #define _VNC_DEBUG 1 |
|
46 |
|
47 #ifdef _VNC_DEBUG |
|
48 #define VNC_DEBUG(fmt, ...) do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0) |
|
49 |
|
50 #if CONFIG_VNC_TLS && _VNC_DEBUG >= 2 |
|
51 /* Very verbose, so only enabled for _VNC_DEBUG >= 2 */ |
|
52 static void vnc_debug_gnutls_log(int level, const char* str) { |
|
53 VNC_DEBUG("%d %s", level, str); |
|
54 } |
|
55 #endif /* CONFIG_VNC_TLS && _VNC_DEBUG */ |
|
56 #else |
|
57 #define VNC_DEBUG(fmt, ...) do { } while (0) |
|
58 #endif |
|
59 |
|
60 /* DFG TODO */ |
|
61 #define kbd_put_keycode gui_notify_term_key |
|
62 /************/ |
|
63 |
|
64 typedef struct Buffer |
|
65 { |
|
66 size_t capacity; |
|
67 size_t offset; |
|
68 uint8_t *buffer; |
|
69 } Buffer; |
|
70 |
|
71 typedef struct VncState VncState; |
|
72 |
|
73 typedef int VncReadEvent(VncState *vs, uint8_t *data, size_t len); |
|
74 |
|
75 typedef void VncWritePixels(VncState *vs, void *data, int size); |
|
76 |
|
77 typedef void VncSendHextileTile(VncState *vs, |
|
78 int x, int y, int w, int h, |
|
79 void *last_bg, |
|
80 void *last_fg, |
|
81 int *has_bg, int *has_fg); |
|
82 |
|
83 #define VNC_MAX_WIDTH 2048 |
|
84 #define VNC_MAX_HEIGHT 2048 |
|
85 #define VNC_DIRTY_WORDS (VNC_MAX_WIDTH / (16 * 32)) |
|
86 |
|
87 #define VNC_AUTH_CHALLENGE_SIZE 16 |
|
88 |
|
89 enum { |
|
90 VNC_AUTH_INVALID = 0, |
|
91 VNC_AUTH_NONE = 1, |
|
92 VNC_AUTH_VNC = 2, |
|
93 VNC_AUTH_RA2 = 5, |
|
94 VNC_AUTH_RA2NE = 6, |
|
95 VNC_AUTH_TIGHT = 16, |
|
96 VNC_AUTH_ULTRA = 17, |
|
97 VNC_AUTH_TLS = 18, |
|
98 VNC_AUTH_VENCRYPT = 19 |
|
99 }; |
|
100 |
|
101 #ifdef CONFIG_VNC_TLS |
|
102 enum { |
|
103 VNC_WIREMODE_CLEAR, |
|
104 VNC_WIREMODE_TLS, |
|
105 }; |
|
106 |
|
107 enum { |
|
108 VNC_AUTH_VENCRYPT_PLAIN = 256, |
|
109 VNC_AUTH_VENCRYPT_TLSNONE = 257, |
|
110 VNC_AUTH_VENCRYPT_TLSVNC = 258, |
|
111 VNC_AUTH_VENCRYPT_TLSPLAIN = 259, |
|
112 VNC_AUTH_VENCRYPT_X509NONE = 260, |
|
113 VNC_AUTH_VENCRYPT_X509VNC = 261, |
|
114 VNC_AUTH_VENCRYPT_X509PLAIN = 262, |
|
115 }; |
|
116 |
|
117 #define X509_CA_CERT_FILE "ca-cert.pem" |
|
118 #define X509_CA_CRL_FILE "ca-crl.pem" |
|
119 #define X509_SERVER_KEY_FILE "server-key.pem" |
|
120 #define X509_SERVER_CERT_FILE "server-cert.pem" |
|
121 |
|
122 #endif /* CONFIG_VNC_TLS */ |
|
123 |
|
124 |
|
125 int kbd_in_terminal_mode; /* DFG TODO: MOVE THIS INTO VncState and implement! */ |
|
126 |
|
127 struct VncState |
|
128 { |
|
129 QEMUTimer *timer; |
|
130 int lsock; |
|
131 int csock; |
|
132 DisplayState *ds; |
|
133 int need_update; |
|
134 int width; |
|
135 int height; |
|
136 uint32_t dirty_row[VNC_MAX_HEIGHT][VNC_DIRTY_WORDS]; |
|
137 char *old_data; |
|
138 int depth; /* internal VNC frame buffer byte per pixel */ |
|
139 int has_resize; |
|
140 int has_hextile; |
|
141 int has_pointer_type_change; |
|
142 int has_WMVi; |
|
143 int absolute; |
|
144 int last_x; |
|
145 int last_y; |
|
146 |
|
147 int major; |
|
148 int minor; |
|
149 |
|
150 char *display; |
|
151 char *password; |
|
152 int auth; |
|
153 #ifdef CONFIG_VNC_TLS |
|
154 int subauth; |
|
155 int x509verify; |
|
156 |
|
157 char *x509cacert; |
|
158 char *x509cacrl; |
|
159 char *x509cert; |
|
160 char *x509key; |
|
161 #endif |
|
162 char challenge[VNC_AUTH_CHALLENGE_SIZE]; |
|
163 |
|
164 #ifdef CONFIG_VNC_TLS |
|
165 int wiremode; |
|
166 gnutls_session_t tls_session; |
|
167 #endif |
|
168 |
|
169 Buffer output; |
|
170 Buffer input; |
|
171 kbd_layout_t *kbd_layout; |
|
172 /* current output mode information */ |
|
173 VncWritePixels *write_pixels; |
|
174 VncSendHextileTile *send_hextile_tile; |
|
175 int pix_bpp, pix_big_endian; |
|
176 int client_red_shift, client_red_max, server_red_shift, server_red_max; |
|
177 int client_green_shift, client_green_max, server_green_shift, server_green_max; |
|
178 int client_blue_shift, client_blue_max, server_blue_shift, server_blue_max; |
|
179 |
|
180 CaptureVoiceOut *audio_cap; |
|
181 struct audsettings as; |
|
182 |
|
183 VncReadEvent *read_handler; |
|
184 size_t read_handler_expect; |
|
185 /* input */ |
|
186 uint8_t modifiers_state[256]; |
|
187 }; |
|
188 |
|
189 static VncState *vnc_state; /* needed for info vnc */ |
|
190 |
|
191 void do_info_vnc(void) |
|
192 { |
|
193 if (vnc_state == NULL || vnc_state->display == NULL) |
|
194 term_printf("VNC server disabled\n"); |
|
195 else { |
|
196 term_printf("VNC server active on: "); |
|
197 term_print_filename(vnc_state->display); |
|
198 term_printf("\n"); |
|
199 |
|
200 if (vnc_state->csock == -1) |
|
201 term_printf("No client connected\n"); |
|
202 else |
|
203 term_printf("Client connected\n"); |
|
204 } |
|
205 } |
|
206 |
|
207 /* TODO |
|
208 1) Get the queue working for IO. |
|
209 2) there is some weirdness when using the -S option (the screen is grey |
|
210 and not totally invalidated |
|
211 3) resolutions > 1024 |
|
212 */ |
|
213 |
|
214 static void vnc_write(VncState *vs, const void *data, size_t len); |
|
215 static void vnc_write_u32(VncState *vs, uint32_t value); |
|
216 static void vnc_write_s32(VncState *vs, int32_t value); |
|
217 static void vnc_write_u16(VncState *vs, uint16_t value); |
|
218 static void vnc_write_u8(VncState *vs, uint8_t value); |
|
219 static void vnc_flush(VncState *vs); |
|
220 static void vnc_update_client(void *opaque); |
|
221 static void vnc_client_read(void *opaque); |
|
222 |
|
223 static void vnc_colordepth(DisplayState *ds, int depth); |
|
224 |
|
225 static inline void vnc_set_bit(uint32_t *d, int k) |
|
226 { |
|
227 d[k >> 5] |= 1 << (k & 0x1f); |
|
228 } |
|
229 |
|
230 static inline void vnc_clear_bit(uint32_t *d, int k) |
|
231 { |
|
232 d[k >> 5] &= ~(1 << (k & 0x1f)); |
|
233 } |
|
234 |
|
235 static inline void vnc_set_bits(uint32_t *d, int n, int nb_words) |
|
236 { |
|
237 int j; |
|
238 |
|
239 j = 0; |
|
240 while (n >= 32) { |
|
241 d[j++] = -1; |
|
242 n -= 32; |
|
243 } |
|
244 if (n > 0) |
|
245 d[j++] = (1 << n) - 1; |
|
246 while (j < nb_words) |
|
247 d[j++] = 0; |
|
248 } |
|
249 |
|
250 static inline int vnc_get_bit(const uint32_t *d, int k) |
|
251 { |
|
252 return (d[k >> 5] >> (k & 0x1f)) & 1; |
|
253 } |
|
254 |
|
255 static inline int vnc_and_bits(const uint32_t *d1, const uint32_t *d2, |
|
256 int nb_words) |
|
257 { |
|
258 int i; |
|
259 for(i = 0; i < nb_words; i++) { |
|
260 if ((d1[i] & d2[i]) != 0) |
|
261 return 1; |
|
262 } |
|
263 return 0; |
|
264 } |
|
265 |
|
266 static void vnc_dpy_update(DisplayState *ds, int x, int y, int w, int h) |
|
267 { |
|
268 VncState *vs = ds->opaque; |
|
269 int i; |
|
270 |
|
271 h += y; |
|
272 |
|
273 /* round x down to ensure the loop only spans one 16-pixel block per, |
|
274 iteration. otherwise, if (x % 16) != 0, the last iteration may span |
|
275 two 16-pixel blocks but we only mark the first as dirty |
|
276 */ |
|
277 w += (x % 16); |
|
278 x -= (x % 16); |
|
279 |
|
280 x = MIN(x, vs->width); |
|
281 y = MIN(y, vs->height); |
|
282 w = MIN(x + w, vs->width) - x; |
|
283 h = MIN(h, vs->height); |
|
284 |
|
285 for (; y < h; y++) |
|
286 for (i = 0; i < w; i += 16) |
|
287 vnc_set_bit(vs->dirty_row[y], (x + i) / 16); |
|
288 } |
|
289 |
|
290 static void vnc_framebuffer_update(VncState *vs, int x, int y, int w, int h, |
|
291 int32_t encoding) |
|
292 { |
|
293 vnc_write_u16(vs, x); |
|
294 vnc_write_u16(vs, y); |
|
295 vnc_write_u16(vs, w); |
|
296 vnc_write_u16(vs, h); |
|
297 |
|
298 vnc_write_s32(vs, encoding); |
|
299 } |
|
300 |
|
301 static void vnc_dpy_resize(DisplayState *ds, int w, int h) |
|
302 { |
|
303 int size_changed; |
|
304 VncState *vs = ds->opaque; |
|
305 |
|
306 ds->data = qemu_realloc(ds->data, w * h * vs->depth); |
|
307 vs->old_data = qemu_realloc(vs->old_data, w * h * vs->depth); |
|
308 |
|
309 if (ds->data == NULL || vs->old_data == NULL) { |
|
310 fprintf(stderr, "vnc: memory allocation failed\n"); |
|
311 exit(1); |
|
312 } |
|
313 |
|
314 if (ds->depth != vs->depth * 8) { |
|
315 ds->depth = vs->depth * 8; |
|
316 console_color_init(ds); |
|
317 } |
|
318 size_changed = ds->width != w || ds->height != h; |
|
319 ds->width = w; |
|
320 ds->height = h; |
|
321 ds->linesize = w * vs->depth; |
|
322 if (size_changed) { |
|
323 vs->width = ds->width; |
|
324 vs->height = ds->height; |
|
325 if (vs->csock != -1 && vs->has_resize) { |
|
326 vnc_write_u8(vs, 0); /* msg id */ |
|
327 vnc_write_u8(vs, 0); |
|
328 vnc_write_u16(vs, 1); /* number of rects */ |
|
329 vnc_framebuffer_update(vs, 0, 0, ds->width, ds->height, -223); |
|
330 vnc_flush(vs); |
|
331 } |
|
332 } |
|
333 |
|
334 memset(vs->dirty_row, 0xFF, sizeof(vs->dirty_row)); |
|
335 memset(vs->old_data, 42, ds_get_linesize(vs->ds) * ds_get_height(vs->ds)); |
|
336 } |
|
337 |
|
338 /* fastest code */ |
|
339 static void vnc_write_pixels_copy(VncState *vs, void *pixels, int size) |
|
340 { |
|
341 vnc_write(vs, pixels, size); |
|
342 } |
|
343 |
|
344 /* slowest but generic code. */ |
|
345 static void vnc_convert_pixel(VncState *vs, uint8_t *buf, uint32_t v) |
|
346 { |
|
347 uint8_t r, g, b; |
|
348 |
|
349 r = ((v >> vs->server_red_shift) & vs->server_red_max) * (vs->client_red_max + 1) / |
|
350 (vs->server_red_max + 1); |
|
351 g = ((v >> vs->server_green_shift) & vs->server_green_max) * (vs->client_green_max + 1) / |
|
352 (vs->server_green_max + 1); |
|
353 b = ((v >> vs->server_blue_shift) & vs->server_blue_max) * (vs->client_blue_max + 1) / |
|
354 (vs->server_blue_max + 1); |
|
355 v = (r << vs->client_red_shift) | |
|
356 (g << vs->client_green_shift) | |
|
357 (b << vs->client_blue_shift); |
|
358 switch(vs->pix_bpp) { |
|
359 case 1: |
|
360 buf[0] = v; |
|
361 break; |
|
362 case 2: |
|
363 if (vs->pix_big_endian) { |
|
364 buf[0] = v >> 8; |
|
365 buf[1] = v; |
|
366 } else { |
|
367 buf[1] = v >> 8; |
|
368 buf[0] = v; |
|
369 } |
|
370 break; |
|
371 default: |
|
372 case 4: |
|
373 if (vs->pix_big_endian) { |
|
374 buf[0] = v >> 24; |
|
375 buf[1] = v >> 16; |
|
376 buf[2] = v >> 8; |
|
377 buf[3] = v; |
|
378 } else { |
|
379 buf[3] = v >> 24; |
|
380 buf[2] = v >> 16; |
|
381 buf[1] = v >> 8; |
|
382 buf[0] = v; |
|
383 } |
|
384 break; |
|
385 } |
|
386 } |
|
387 |
|
388 static void vnc_write_pixels_generic(VncState *vs, void *pixels1, int size) |
|
389 { |
|
390 uint8_t buf[4]; |
|
391 |
|
392 if (vs->depth == 4) { |
|
393 uint32_t *pixels = pixels1; |
|
394 int n, i; |
|
395 n = size >> 2; |
|
396 for(i = 0; i < n; i++) { |
|
397 vnc_convert_pixel(vs, buf, pixels[i]); |
|
398 vnc_write(vs, buf, vs->pix_bpp); |
|
399 } |
|
400 } else if (vs->depth == 2) { |
|
401 uint16_t *pixels = pixels1; |
|
402 int n, i; |
|
403 n = size >> 1; |
|
404 for(i = 0; i < n; i++) { |
|
405 vnc_convert_pixel(vs, buf, pixels[i]); |
|
406 vnc_write(vs, buf, vs->pix_bpp); |
|
407 } |
|
408 } else if (vs->depth == 1) { |
|
409 uint8_t *pixels = pixels1; |
|
410 int n, i; |
|
411 n = size; |
|
412 for(i = 0; i < n; i++) { |
|
413 vnc_convert_pixel(vs, buf, pixels[i]); |
|
414 vnc_write(vs, buf, vs->pix_bpp); |
|
415 } |
|
416 } else { |
|
417 fprintf(stderr, "vnc_write_pixels_generic: VncState color depth not supported\n"); |
|
418 } |
|
419 } |
|
420 |
|
421 static void send_framebuffer_update_raw(VncState *vs, int x, int y, int w, int h) |
|
422 { |
|
423 int i; |
|
424 uint8_t *row; |
|
425 |
|
426 vnc_framebuffer_update(vs, x, y, w, h, 0); |
|
427 |
|
428 row = ds_get_data(vs->ds) + y * ds_get_linesize(vs->ds) + x * vs->depth; |
|
429 for (i = 0; i < h; i++) { |
|
430 vs->write_pixels(vs, row, w * vs->depth); |
|
431 row += ds_get_linesize(vs->ds); |
|
432 } |
|
433 } |
|
434 |
|
435 static void hextile_enc_cord(uint8_t *ptr, int x, int y, int w, int h) |
|
436 { |
|
437 ptr[0] = ((x & 0x0F) << 4) | (y & 0x0F); |
|
438 ptr[1] = (((w - 1) & 0x0F) << 4) | ((h - 1) & 0x0F); |
|
439 } |
|
440 |
|
441 #define BPP 8 |
|
442 #include "vnchextile.h" |
|
443 #undef BPP |
|
444 |
|
445 #define BPP 16 |
|
446 #include "vnchextile.h" |
|
447 #undef BPP |
|
448 |
|
449 #define BPP 32 |
|
450 #include "vnchextile.h" |
|
451 #undef BPP |
|
452 |
|
453 #define GENERIC |
|
454 #define BPP 8 |
|
455 #include "vnchextile.h" |
|
456 #undef BPP |
|
457 #undef GENERIC |
|
458 |
|
459 #define GENERIC |
|
460 #define BPP 16 |
|
461 #include "vnchextile.h" |
|
462 #undef BPP |
|
463 #undef GENERIC |
|
464 |
|
465 #define GENERIC |
|
466 #define BPP 32 |
|
467 #include "vnchextile.h" |
|
468 #undef BPP |
|
469 #undef GENERIC |
|
470 |
|
471 static void send_framebuffer_update_hextile(VncState *vs, int x, int y, int w, int h) |
|
472 { |
|
473 int i, j; |
|
474 int has_fg, has_bg; |
|
475 uint8_t *last_fg, *last_bg; |
|
476 |
|
477 vnc_framebuffer_update(vs, x, y, w, h, 5); |
|
478 |
|
479 last_fg = (uint8_t *) malloc(vs->depth); |
|
480 last_bg = (uint8_t *) malloc(vs->depth); |
|
481 has_fg = has_bg = 0; |
|
482 for (j = y; j < (y + h); j += 16) { |
|
483 for (i = x; i < (x + w); i += 16) { |
|
484 vs->send_hextile_tile(vs, i, j, |
|
485 MIN(16, x + w - i), MIN(16, y + h - j), |
|
486 last_bg, last_fg, &has_bg, &has_fg); |
|
487 } |
|
488 } |
|
489 free(last_fg); |
|
490 free(last_bg); |
|
491 |
|
492 } |
|
493 |
|
494 static void send_framebuffer_update(VncState *vs, int x, int y, int w, int h) |
|
495 { |
|
496 if (vs->has_hextile) |
|
497 send_framebuffer_update_hextile(vs, x, y, w, h); |
|
498 else |
|
499 send_framebuffer_update_raw(vs, x, y, w, h); |
|
500 } |
|
501 |
|
502 static void vnc_copy(DisplayState *ds, int src_x, int src_y, int dst_x, int dst_y, int w, int h) |
|
503 { |
|
504 int src, dst; |
|
505 uint8_t *src_row; |
|
506 uint8_t *dst_row; |
|
507 char *old_row; |
|
508 int y = 0; |
|
509 int pitch = ds_get_linesize(ds); |
|
510 VncState *vs = ds->opaque; |
|
511 |
|
512 vnc_update_client(vs); |
|
513 |
|
514 if (dst_y > src_y) { |
|
515 y = h - 1; |
|
516 pitch = -pitch; |
|
517 } |
|
518 |
|
519 src = (ds_get_linesize(ds) * (src_y + y) + vs->depth * src_x); |
|
520 dst = (ds_get_linesize(ds) * (dst_y + y) + vs->depth * dst_x); |
|
521 |
|
522 src_row = ds_get_data(ds) + src; |
|
523 dst_row = ds_get_data(ds) + dst; |
|
524 old_row = vs->old_data + dst; |
|
525 |
|
526 for (y = 0; y < h; y++) { |
|
527 memmove(old_row, src_row, w * vs->depth); |
|
528 memmove(dst_row, src_row, w * vs->depth); |
|
529 src_row += pitch; |
|
530 dst_row += pitch; |
|
531 old_row += pitch; |
|
532 } |
|
533 |
|
534 vnc_write_u8(vs, 0); /* msg id */ |
|
535 vnc_write_u8(vs, 0); |
|
536 vnc_write_u16(vs, 1); /* number of rects */ |
|
537 vnc_framebuffer_update(vs, dst_x, dst_y, w, h, 1); |
|
538 vnc_write_u16(vs, src_x); |
|
539 vnc_write_u16(vs, src_y); |
|
540 vnc_flush(vs); |
|
541 } |
|
542 |
|
543 static int find_dirty_height(VncState *vs, int y, int last_x, int x) |
|
544 { |
|
545 int h; |
|
546 |
|
547 for (h = 1; h < (vs->height - y); h++) { |
|
548 int tmp_x; |
|
549 if (!vnc_get_bit(vs->dirty_row[y + h], last_x)) |
|
550 break; |
|
551 for (tmp_x = last_x; tmp_x < x; tmp_x++) |
|
552 vnc_clear_bit(vs->dirty_row[y + h], tmp_x); |
|
553 } |
|
554 |
|
555 return h; |
|
556 } |
|
557 |
|
558 static void vnc_update_client(void *opaque) |
|
559 { |
|
560 VncState *vs = opaque; |
|
561 |
|
562 if (vs->need_update && vs->csock != -1) { |
|
563 int y; |
|
564 uint8_t *row; |
|
565 char *old_row; |
|
566 uint32_t width_mask[VNC_DIRTY_WORDS]; |
|
567 int n_rectangles; |
|
568 int saved_offset; |
|
569 int has_dirty = 0; |
|
570 |
|
571 #if 0 |
|
572 TODO CHECK DFG |
|
573 vga_hw_update(); |
|
574 #endif |
|
575 |
|
576 vnc_set_bits(width_mask, (vs->width / 16), VNC_DIRTY_WORDS); |
|
577 |
|
578 /* Walk through the dirty map and eliminate tiles that |
|
579 really aren't dirty */ |
|
580 row = ds_get_data(vs->ds); |
|
581 old_row = vs->old_data; |
|
582 |
|
583 for (y = 0; y < vs->height; y++) { |
|
584 if (vnc_and_bits(vs->dirty_row[y], width_mask, VNC_DIRTY_WORDS)) { |
|
585 int x; |
|
586 uint8_t *ptr; |
|
587 char *old_ptr; |
|
588 |
|
589 ptr = row; |
|
590 old_ptr = (char*)old_row; |
|
591 |
|
592 for (x = 0; x < ds_get_width(vs->ds); x += 16) { |
|
593 if (memcmp(old_ptr, ptr, 16 * vs->depth) == 0) { |
|
594 vnc_clear_bit(vs->dirty_row[y], (x / 16)); |
|
595 } else { |
|
596 has_dirty = 1; |
|
597 memcpy(old_ptr, ptr, 16 * vs->depth); |
|
598 } |
|
599 |
|
600 ptr += 16 * vs->depth; |
|
601 old_ptr += 16 * vs->depth; |
|
602 } |
|
603 } |
|
604 |
|
605 row += ds_get_linesize(vs->ds); |
|
606 old_row += ds_get_linesize(vs->ds); |
|
607 } |
|
608 |
|
609 if (!has_dirty && !vs->audio_cap) { |
|
610 qemu_mod_timer(vs->timer, qemu_get_clock(rt_clock) + VNC_REFRESH_INTERVAL); |
|
611 return; |
|
612 } |
|
613 |
|
614 /* Count rectangles */ |
|
615 n_rectangles = 0; |
|
616 vnc_write_u8(vs, 0); /* msg id */ |
|
617 vnc_write_u8(vs, 0); |
|
618 saved_offset = vs->output.offset; |
|
619 vnc_write_u16(vs, 0); |
|
620 |
|
621 for (y = 0; y < vs->height; y++) { |
|
622 int x; |
|
623 int last_x = -1; |
|
624 for (x = 0; x < vs->width / 16; x++) { |
|
625 if (vnc_get_bit(vs->dirty_row[y], x)) { |
|
626 if (last_x == -1) { |
|
627 last_x = x; |
|
628 } |
|
629 vnc_clear_bit(vs->dirty_row[y], x); |
|
630 } else { |
|
631 if (last_x != -1) { |
|
632 int h = find_dirty_height(vs, y, last_x, x); |
|
633 send_framebuffer_update(vs, last_x * 16, y, (x - last_x) * 16, h); |
|
634 n_rectangles++; |
|
635 } |
|
636 last_x = -1; |
|
637 } |
|
638 } |
|
639 if (last_x != -1) { |
|
640 int h = find_dirty_height(vs, y, last_x, x); |
|
641 send_framebuffer_update(vs, last_x * 16, y, (x - last_x) * 16, h); |
|
642 n_rectangles++; |
|
643 } |
|
644 } |
|
645 vs->output.buffer[saved_offset] = (n_rectangles >> 8) & 0xFF; |
|
646 vs->output.buffer[saved_offset + 1] = n_rectangles & 0xFF; |
|
647 vnc_flush(vs); |
|
648 |
|
649 } |
|
650 |
|
651 if (vs->csock != -1) { |
|
652 qemu_mod_timer(vs->timer, qemu_get_clock(rt_clock) + VNC_REFRESH_INTERVAL); |
|
653 } |
|
654 |
|
655 } |
|
656 |
|
657 static int vnc_listen_poll(void *opaque) |
|
658 { |
|
659 VncState *vs = opaque; |
|
660 if (vs->csock == -1) |
|
661 return 1; |
|
662 return 0; |
|
663 } |
|
664 |
|
665 static void buffer_reserve(Buffer *buffer, size_t len) |
|
666 { |
|
667 if ((buffer->capacity - buffer->offset) < len) { |
|
668 buffer->capacity += (len + 1024); |
|
669 buffer->buffer = qemu_realloc(buffer->buffer, buffer->capacity); |
|
670 if (buffer->buffer == NULL) { |
|
671 fprintf(stderr, "vnc: out of memory\n"); |
|
672 exit(1); |
|
673 } |
|
674 } |
|
675 } |
|
676 |
|
677 static int buffer_empty(Buffer *buffer) |
|
678 { |
|
679 return buffer->offset == 0; |
|
680 } |
|
681 |
|
682 static uint8_t *buffer_end(Buffer *buffer) |
|
683 { |
|
684 return buffer->buffer + buffer->offset; |
|
685 } |
|
686 |
|
687 static void buffer_reset(Buffer *buffer) |
|
688 { |
|
689 buffer->offset = 0; |
|
690 } |
|
691 |
|
692 static void buffer_append(Buffer *buffer, const void *data, size_t len) |
|
693 { |
|
694 memcpy(buffer->buffer + buffer->offset, data, len); |
|
695 buffer->offset += len; |
|
696 } |
|
697 |
|
698 /* audio */ |
|
699 static void audio_capture_notify(void *opaque, audcnotification_e cmd) |
|
700 { |
|
701 VncState *vs = opaque; |
|
702 |
|
703 switch (cmd) { |
|
704 case AUD_CNOTIFY_DISABLE: |
|
705 vnc_write_u8(vs, 255); |
|
706 vnc_write_u8(vs, 1); |
|
707 vnc_write_u16(vs, 0); |
|
708 vnc_flush(vs); |
|
709 break; |
|
710 |
|
711 case AUD_CNOTIFY_ENABLE: |
|
712 vnc_write_u8(vs, 255); |
|
713 vnc_write_u8(vs, 1); |
|
714 vnc_write_u16(vs, 1); |
|
715 vnc_flush(vs); |
|
716 break; |
|
717 } |
|
718 } |
|
719 |
|
720 static void audio_capture_destroy(void *opaque) |
|
721 { |
|
722 } |
|
723 |
|
724 static void audio_capture(void *opaque, void *buf, int size) |
|
725 { |
|
726 VncState *vs = opaque; |
|
727 |
|
728 vnc_write_u8(vs, 255); |
|
729 vnc_write_u8(vs, 1); |
|
730 vnc_write_u16(vs, 2); |
|
731 vnc_write_u32(vs, size); |
|
732 vnc_write(vs, buf, size); |
|
733 vnc_flush(vs); |
|
734 } |
|
735 |
|
736 static void audio_add(VncState *vs) |
|
737 { |
|
738 struct audio_capture_ops ops; |
|
739 |
|
740 if (vs->audio_cap) { |
|
741 term_printf ("audio already running\n"); |
|
742 return; |
|
743 } |
|
744 |
|
745 ops.notify = audio_capture_notify; |
|
746 ops.destroy = audio_capture_destroy; |
|
747 ops.capture = audio_capture; |
|
748 |
|
749 vs->audio_cap = AUD_add_capture(NULL, &vs->as, &ops, vs); |
|
750 if (!vs->audio_cap) { |
|
751 term_printf ("Failed to add audio capture\n"); |
|
752 } |
|
753 } |
|
754 |
|
755 static void audio_del(VncState *vs) |
|
756 { |
|
757 if (vs->audio_cap) { |
|
758 AUD_del_capture(vs->audio_cap, vs); |
|
759 vs->audio_cap = NULL; |
|
760 } |
|
761 } |
|
762 |
|
763 static int vnc_client_io_error(VncState *vs, int ret, int last_errno) |
|
764 { |
|
765 if (ret == 0 || ret == -1) { |
|
766 if (ret == -1) { |
|
767 switch (last_errno) { |
|
768 case EINTR: |
|
769 case EAGAIN: |
|
770 #ifdef _WIN32 |
|
771 case WSAEWOULDBLOCK: |
|
772 #endif |
|
773 return 0; |
|
774 default: |
|
775 break; |
|
776 } |
|
777 } |
|
778 |
|
779 VNC_DEBUG("Closing down client sock %d %d\n", ret, ret < 0 ? last_errno : 0); |
|
780 qemu_set_fd_handler2(vs->csock, NULL, NULL, NULL, NULL); |
|
781 closesocket(vs->csock); |
|
782 vs->csock = -1; |
|
783 gui_notify_idle(1); |
|
784 /*vs->ds->idle = 1;*/ |
|
785 buffer_reset(&vs->input); |
|
786 buffer_reset(&vs->output); |
|
787 vs->need_update = 0; |
|
788 #ifdef CONFIG_VNC_TLS |
|
789 if (vs->tls_session) { |
|
790 gnutls_deinit(vs->tls_session); |
|
791 vs->tls_session = NULL; |
|
792 } |
|
793 vs->wiremode = VNC_WIREMODE_CLEAR; |
|
794 #endif /* CONFIG_VNC_TLS */ |
|
795 audio_del(vs); |
|
796 return 0; |
|
797 } |
|
798 return ret; |
|
799 } |
|
800 |
|
801 static void vnc_client_error(VncState *vs) |
|
802 { |
|
803 vnc_client_io_error(vs, -1, EINVAL); |
|
804 } |
|
805 |
|
806 static void vnc_client_write(void *opaque) |
|
807 { |
|
808 long ret; |
|
809 VncState *vs = opaque; |
|
810 |
|
811 #ifdef CONFIG_VNC_TLS |
|
812 if (vs->tls_session) { |
|
813 ret = gnutls_write(vs->tls_session, vs->output.buffer, vs->output.offset); |
|
814 if (ret < 0) { |
|
815 if (ret == GNUTLS_E_AGAIN) |
|
816 errno = EAGAIN; |
|
817 else |
|
818 errno = EIO; |
|
819 ret = -1; |
|
820 } |
|
821 } else |
|
822 #endif /* CONFIG_VNC_TLS */ |
|
823 ret = send(vs->csock, vs->output.buffer, vs->output.offset, 0); |
|
824 ret = vnc_client_io_error(vs, ret, socket_error()); |
|
825 if (!ret) |
|
826 return; |
|
827 |
|
828 memmove(vs->output.buffer, vs->output.buffer + ret, (vs->output.offset - ret)); |
|
829 vs->output.offset -= ret; |
|
830 |
|
831 if (vs->output.offset == 0) { |
|
832 qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs); |
|
833 } |
|
834 } |
|
835 |
|
836 static void vnc_read_when(VncState *vs, VncReadEvent *func, size_t expecting) |
|
837 { |
|
838 vs->read_handler = func; |
|
839 vs->read_handler_expect = expecting; |
|
840 } |
|
841 |
|
842 static void vnc_client_read(void *opaque) |
|
843 { |
|
844 VncState *vs = opaque; |
|
845 long ret; |
|
846 |
|
847 buffer_reserve(&vs->input, 4096); |
|
848 |
|
849 #ifdef CONFIG_VNC_TLS |
|
850 if (vs->tls_session) { |
|
851 ret = gnutls_read(vs->tls_session, buffer_end(&vs->input), 4096); |
|
852 if (ret < 0) { |
|
853 if (ret == GNUTLS_E_AGAIN) |
|
854 errno = EAGAIN; |
|
855 else |
|
856 errno = EIO; |
|
857 ret = -1; |
|
858 } |
|
859 } else |
|
860 #endif /* CONFIG_VNC_TLS */ |
|
861 ret = recv(vs->csock, buffer_end(&vs->input), 4096, 0); |
|
862 ret = vnc_client_io_error(vs, ret, socket_error()); |
|
863 if (!ret) |
|
864 return; |
|
865 |
|
866 vs->input.offset += ret; |
|
867 |
|
868 while (vs->read_handler && vs->input.offset >= vs->read_handler_expect) { |
|
869 size_t len = vs->read_handler_expect; |
|
870 int ret; |
|
871 |
|
872 ret = vs->read_handler(vs, vs->input.buffer, len); |
|
873 if (vs->csock == -1) |
|
874 return; |
|
875 |
|
876 if (!ret) { |
|
877 memmove(vs->input.buffer, vs->input.buffer + len, (vs->input.offset - len)); |
|
878 vs->input.offset -= len; |
|
879 } else { |
|
880 vs->read_handler_expect = ret; |
|
881 } |
|
882 } |
|
883 } |
|
884 |
|
885 static void vnc_write(VncState *vs, const void *data, size_t len) |
|
886 { |
|
887 buffer_reserve(&vs->output, len); |
|
888 |
|
889 if (buffer_empty(&vs->output)) { |
|
890 qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, vnc_client_write, vs); |
|
891 } |
|
892 |
|
893 buffer_append(&vs->output, data, len); |
|
894 } |
|
895 |
|
896 static void vnc_write_s32(VncState *vs, int32_t value) |
|
897 { |
|
898 vnc_write_u32(vs, *(uint32_t *)&value); |
|
899 } |
|
900 |
|
901 static void vnc_write_u32(VncState *vs, uint32_t value) |
|
902 { |
|
903 uint8_t buf[4]; |
|
904 |
|
905 buf[0] = (value >> 24) & 0xFF; |
|
906 buf[1] = (value >> 16) & 0xFF; |
|
907 buf[2] = (value >> 8) & 0xFF; |
|
908 buf[3] = value & 0xFF; |
|
909 |
|
910 vnc_write(vs, buf, 4); |
|
911 } |
|
912 |
|
913 static void vnc_write_u16(VncState *vs, uint16_t value) |
|
914 { |
|
915 uint8_t buf[2]; |
|
916 |
|
917 buf[0] = (value >> 8) & 0xFF; |
|
918 buf[1] = value & 0xFF; |
|
919 |
|
920 vnc_write(vs, buf, 2); |
|
921 } |
|
922 |
|
923 static void vnc_write_u8(VncState *vs, uint8_t value) |
|
924 { |
|
925 vnc_write(vs, (char *)&value, 1); |
|
926 } |
|
927 |
|
928 static void vnc_flush(VncState *vs) |
|
929 { |
|
930 if (vs->output.offset) |
|
931 vnc_client_write(vs); |
|
932 } |
|
933 |
|
934 static uint8_t read_u8(uint8_t *data, size_t offset) |
|
935 { |
|
936 return data[offset]; |
|
937 } |
|
938 |
|
939 static uint16_t read_u16(uint8_t *data, size_t offset) |
|
940 { |
|
941 return ((data[offset] & 0xFF) << 8) | (data[offset + 1] & 0xFF); |
|
942 } |
|
943 |
|
944 static int32_t read_s32(uint8_t *data, size_t offset) |
|
945 { |
|
946 return (int32_t)((data[offset] << 24) | (data[offset + 1] << 16) | |
|
947 (data[offset + 2] << 8) | data[offset + 3]); |
|
948 } |
|
949 |
|
950 static uint32_t read_u32(uint8_t *data, size_t offset) |
|
951 { |
|
952 return ((data[offset] << 24) | (data[offset + 1] << 16) | |
|
953 (data[offset + 2] << 8) | data[offset + 3]); |
|
954 } |
|
955 |
|
956 #ifdef CONFIG_VNC_TLS |
|
957 static ssize_t vnc_tls_push(gnutls_transport_ptr_t transport, |
|
958 const void *data, |
|
959 size_t len) { |
|
960 struct VncState *vs = (struct VncState *)transport; |
|
961 int ret; |
|
962 |
|
963 retry: |
|
964 ret = send(vs->csock, data, len, 0); |
|
965 if (ret < 0) { |
|
966 if (errno == EINTR) |
|
967 goto retry; |
|
968 return -1; |
|
969 } |
|
970 return ret; |
|
971 } |
|
972 |
|
973 |
|
974 static ssize_t vnc_tls_pull(gnutls_transport_ptr_t transport, |
|
975 void *data, |
|
976 size_t len) { |
|
977 struct VncState *vs = (struct VncState *)transport; |
|
978 int ret; |
|
979 |
|
980 retry: |
|
981 ret = recv(vs->csock, data, len, 0); |
|
982 if (ret < 0) { |
|
983 if (errno == EINTR) |
|
984 goto retry; |
|
985 return -1; |
|
986 } |
|
987 return ret; |
|
988 } |
|
989 #endif /* CONFIG_VNC_TLS */ |
|
990 |
|
991 static void client_cut_text(VncState *vs, size_t len, uint8_t *text) |
|
992 { |
|
993 } |
|
994 |
|
995 static void check_pointer_type_change(VncState *vs, int absolute) |
|
996 { |
|
997 if (vs->has_pointer_type_change && vs->absolute != absolute) { |
|
998 vnc_write_u8(vs, 0); |
|
999 vnc_write_u8(vs, 0); |
|
1000 vnc_write_u16(vs, 1); |
|
1001 vnc_framebuffer_update(vs, absolute, 0, |
|
1002 ds_get_width(vs->ds), ds_get_height(vs->ds), -257); |
|
1003 vnc_flush(vs); |
|
1004 } |
|
1005 vs->absolute = absolute; |
|
1006 } |
|
1007 |
|
1008 static void pointer_event(VncState *vs, int button_mask, int x, int y) |
|
1009 { |
|
1010 int buttons = 0; |
|
1011 int dz = 0; |
|
1012 |
|
1013 if (button_mask & 0x01) |
|
1014 buttons |= MOUSE_EVENT_LBUTTON; |
|
1015 if (button_mask & 0x02) |
|
1016 buttons |= MOUSE_EVENT_MBUTTON; |
|
1017 if (button_mask & 0x04) |
|
1018 buttons |= MOUSE_EVENT_RBUTTON; |
|
1019 if (button_mask & 0x08) |
|
1020 dz = -1; |
|
1021 if (button_mask & 0x10) |
|
1022 dz = 1; |
|
1023 |
|
1024 if (vs->absolute) { |
|
1025 kbd_mouse_event(x * 0x7FFF / (ds_get_width(vs->ds) - 1), |
|
1026 y * 0x7FFF / (ds_get_height(vs->ds) - 1), |
|
1027 dz, buttons); |
|
1028 } else if (vs->has_pointer_type_change) { |
|
1029 x -= 0x7FFF; |
|
1030 y -= 0x7FFF; |
|
1031 |
|
1032 kbd_mouse_event(x, y, dz, buttons); |
|
1033 } else { |
|
1034 if (vs->last_x != -1) |
|
1035 kbd_mouse_event(x - vs->last_x, |
|
1036 y - vs->last_y, |
|
1037 dz, buttons); |
|
1038 vs->last_x = x; |
|
1039 vs->last_y = y; |
|
1040 } |
|
1041 |
|
1042 check_pointer_type_change(vs, kbd_mouse_is_absolute()); |
|
1043 } |
|
1044 |
|
1045 static void reset_keys(VncState *vs) |
|
1046 { |
|
1047 int i; |
|
1048 for(i = 0; i < 256; i++) { |
|
1049 if (vs->modifiers_state[i]) { |
|
1050 if (i & 0x80) |
|
1051 kbd_put_keycode(0xe0); |
|
1052 kbd_put_keycode(i | 0x80); |
|
1053 vs->modifiers_state[i] = 0; |
|
1054 } |
|
1055 } |
|
1056 } |
|
1057 |
|
1058 static void press_key(VncState *vs, int keysym) |
|
1059 { |
|
1060 kbd_put_keycode(keysym2scancode(vs->kbd_layout, keysym) & 0x7f); |
|
1061 kbd_put_keycode(keysym2scancode(vs->kbd_layout, keysym) | 0x80); |
|
1062 } |
|
1063 |
|
1064 static void do_key_event(VncState *vs, int down, int keycode, int sym) |
|
1065 { |
|
1066 /* QEMU console switch */ |
|
1067 switch(keycode) { |
|
1068 case 0x2a: /* Left Shift */ |
|
1069 case 0x36: /* Right Shift */ |
|
1070 case 0x1d: /* Left CTRL */ |
|
1071 case 0x9d: /* Right CTRL */ |
|
1072 case 0x38: /* Left ALT */ |
|
1073 case 0xb8: /* Right ALT */ |
|
1074 if (down) |
|
1075 vs->modifiers_state[keycode] = 1; |
|
1076 else |
|
1077 vs->modifiers_state[keycode] = 0; |
|
1078 break; |
|
1079 case 0x02 ... 0x0a: /* '1' to '9' keys */ |
|
1080 if (down && vs->modifiers_state[0x1d] && vs->modifiers_state[0x38]) { |
|
1081 /* Reset the modifiers sent to the current console */ |
|
1082 reset_keys(vs); |
|
1083 gui_notify_console_select(keycode - 0x02); |
|
1084 return; |
|
1085 } |
|
1086 break; |
|
1087 case 0x3a: /* CapsLock */ |
|
1088 case 0x45: /* NumLock */ |
|
1089 if (!down) |
|
1090 vs->modifiers_state[keycode] ^= 1; |
|
1091 break; |
|
1092 } |
|
1093 |
|
1094 if (keycode_is_keypad(vs->kbd_layout, keycode)) { |
|
1095 /* If the numlock state needs to change then simulate an additional |
|
1096 keypress before sending this one. This will happen if the user |
|
1097 toggles numlock away from the VNC window. |
|
1098 */ |
|
1099 if (keysym_is_numlock(vs->kbd_layout, sym & 0xFFFF)) { |
|
1100 if (!vs->modifiers_state[0x45]) { |
|
1101 vs->modifiers_state[0x45] = 1; |
|
1102 press_key(vs, 0xff7f); |
|
1103 } |
|
1104 } else { |
|
1105 if (vs->modifiers_state[0x45]) { |
|
1106 vs->modifiers_state[0x45] = 0; |
|
1107 press_key(vs, 0xff7f); |
|
1108 } |
|
1109 } |
|
1110 } |
|
1111 |
|
1112 if (/*gui_is_graphic_console() DFG TODO */ !kbd_in_terminal_mode) { |
|
1113 if (keycode & 0x80) |
|
1114 kbd_put_keycode(0xe0); |
|
1115 if (down) |
|
1116 kbd_put_keycode(keycode & 0x7f); |
|
1117 else |
|
1118 kbd_put_keycode(keycode | 0x80); |
|
1119 } else { |
|
1120 /* QEMU console emulation */ |
|
1121 if (down) { |
|
1122 switch (keycode) { |
|
1123 case 0x2a: /* Left Shift */ |
|
1124 case 0x36: /* Right Shift */ |
|
1125 case 0x1d: /* Left CTRL */ |
|
1126 case 0x9d: /* Right CTRL */ |
|
1127 case 0x38: /* Left ALT */ |
|
1128 case 0xb8: /* Right ALT */ |
|
1129 break; |
|
1130 case 0xc8: |
|
1131 gui_notify_term_key(QEMU_KEY_UP); |
|
1132 break; |
|
1133 case 0xd0: |
|
1134 gui_notify_term_key(QEMU_KEY_DOWN); |
|
1135 break; |
|
1136 case 0xcb: |
|
1137 gui_notify_term_key(QEMU_KEY_LEFT); |
|
1138 break; |
|
1139 case 0xcd: |
|
1140 gui_notify_term_key(QEMU_KEY_RIGHT); |
|
1141 break; |
|
1142 case 0xd3: |
|
1143 gui_notify_term_key(QEMU_KEY_DELETE); |
|
1144 break; |
|
1145 case 0xc7: |
|
1146 gui_notify_term_key(QEMU_KEY_HOME); |
|
1147 break; |
|
1148 case 0xcf: |
|
1149 gui_notify_term_key(QEMU_KEY_END); |
|
1150 break; |
|
1151 case 0xc9: |
|
1152 gui_notify_term_key(QEMU_KEY_PAGEUP); |
|
1153 break; |
|
1154 case 0xd1: |
|
1155 gui_notify_term_key(QEMU_KEY_PAGEDOWN); |
|
1156 break; |
|
1157 default: |
|
1158 gui_notify_term_key(sym); |
|
1159 break; |
|
1160 } |
|
1161 } |
|
1162 } |
|
1163 } |
|
1164 |
|
1165 static void key_event(VncState *vs, int down, uint32_t sym) |
|
1166 { |
|
1167 int keycode; |
|
1168 |
|
1169 if (sym >= 'A' && sym <= 'Z' && /*gui_is_graphic_console()*/ !kbd_in_terminal_mode) |
|
1170 sym = sym - 'A' + 'a'; |
|
1171 |
|
1172 keycode = keysym2scancode(vs->kbd_layout, sym & 0xFFFF); |
|
1173 do_key_event(vs, down, keycode, sym); |
|
1174 } |
|
1175 |
|
1176 static void ext_key_event(VncState *vs, int down, |
|
1177 uint32_t sym, uint16_t keycode) |
|
1178 { |
|
1179 /* if the user specifies a keyboard layout, always use it */ |
|
1180 if (keyboard_layout) |
|
1181 key_event(vs, down, sym); |
|
1182 else |
|
1183 do_key_event(vs, down, keycode, sym); |
|
1184 } |
|
1185 |
|
1186 static void framebuffer_update_request(VncState *vs, int incremental, |
|
1187 int x_position, int y_position, |
|
1188 int w, int h) |
|
1189 { |
|
1190 if (x_position > ds_get_width(vs->ds)) |
|
1191 x_position = ds_get_width(vs->ds); |
|
1192 if (y_position > ds_get_height(vs->ds)) |
|
1193 y_position = ds_get_height(vs->ds); |
|
1194 if (x_position + w >= ds_get_width(vs->ds)) |
|
1195 w = ds_get_width(vs->ds) - x_position; |
|
1196 if (y_position + h >= ds_get_height(vs->ds)) |
|
1197 h = ds_get_height(vs->ds) - y_position; |
|
1198 |
|
1199 int i; |
|
1200 vs->need_update = 1; |
|
1201 if (!incremental) { |
|
1202 char *old_row = vs->old_data + y_position * ds_get_linesize(vs->ds); |
|
1203 |
|
1204 for (i = 0; i < h; i++) { |
|
1205 vnc_set_bits(vs->dirty_row[y_position + i], |
|
1206 (ds_get_width(vs->ds) / 16), VNC_DIRTY_WORDS); |
|
1207 memset(old_row, 42, ds_get_width(vs->ds) * vs->depth); |
|
1208 old_row += ds_get_linesize(vs->ds); |
|
1209 } |
|
1210 } |
|
1211 } |
|
1212 |
|
1213 static void send_ext_key_event_ack(VncState *vs) |
|
1214 { |
|
1215 vnc_write_u8(vs, 0); |
|
1216 vnc_write_u8(vs, 0); |
|
1217 vnc_write_u16(vs, 1); |
|
1218 vnc_framebuffer_update(vs, 0, 0, ds_get_width(vs->ds), ds_get_height(vs->ds), -258); |
|
1219 vnc_flush(vs); |
|
1220 } |
|
1221 |
|
1222 static void send_ext_audio_ack(VncState *vs) |
|
1223 { |
|
1224 vnc_write_u8(vs, 0); |
|
1225 vnc_write_u8(vs, 0); |
|
1226 vnc_write_u16(vs, 1); |
|
1227 vnc_framebuffer_update(vs, 0, 0, ds_get_width(vs->ds), ds_get_height(vs->ds), -259); |
|
1228 vnc_flush(vs); |
|
1229 } |
|
1230 |
|
1231 static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings) |
|
1232 { |
|
1233 int i; |
|
1234 |
|
1235 vs->has_hextile = 0; |
|
1236 vs->has_resize = 0; |
|
1237 vs->has_pointer_type_change = 0; |
|
1238 vs->has_WMVi = 0; |
|
1239 vs->absolute = -1; |
|
1240 vs->ds->dpy_copy = NULL; |
|
1241 |
|
1242 for (i = n_encodings - 1; i >= 0; i--) { |
|
1243 switch (encodings[i]) { |
|
1244 case 0: /* Raw */ |
|
1245 vs->has_hextile = 0; |
|
1246 break; |
|
1247 case 1: /* CopyRect */ |
|
1248 vs->ds->dpy_copy = vnc_copy; |
|
1249 break; |
|
1250 case 5: /* Hextile */ |
|
1251 vs->has_hextile = 1; |
|
1252 break; |
|
1253 case -223: /* DesktopResize */ |
|
1254 vs->has_resize = 1; |
|
1255 break; |
|
1256 case -257: |
|
1257 vs->has_pointer_type_change = 1; |
|
1258 break; |
|
1259 case -258: |
|
1260 send_ext_key_event_ack(vs); |
|
1261 break; |
|
1262 case -259: |
|
1263 send_ext_audio_ack(vs); |
|
1264 break; |
|
1265 case 0x574D5669: |
|
1266 vs->has_WMVi = 1; |
|
1267 break; |
|
1268 default: |
|
1269 break; |
|
1270 } |
|
1271 } |
|
1272 |
|
1273 check_pointer_type_change(vs, kbd_mouse_is_absolute()); |
|
1274 } |
|
1275 |
|
1276 static void set_pixel_format(VncState *vs, |
|
1277 int bits_per_pixel, int depth, |
|
1278 int big_endian_flag, int true_color_flag, |
|
1279 int red_max, int green_max, int blue_max, |
|
1280 int red_shift, int green_shift, int blue_shift) |
|
1281 { |
|
1282 int host_big_endian_flag; |
|
1283 |
|
1284 #ifdef WORDS_BIGENDIAN |
|
1285 host_big_endian_flag = 1; |
|
1286 #else |
|
1287 host_big_endian_flag = 0; |
|
1288 #endif |
|
1289 if (!true_color_flag) { |
|
1290 fail: |
|
1291 vnc_client_error(vs); |
|
1292 return; |
|
1293 } |
|
1294 if (bits_per_pixel == 32 && |
|
1295 bits_per_pixel == vs->depth * 8 && |
|
1296 host_big_endian_flag == big_endian_flag && |
|
1297 red_max == 0xff && green_max == 0xff && blue_max == 0xff && |
|
1298 red_shift == 16 && green_shift == 8 && blue_shift == 0) { |
|
1299 vs->depth = 4; |
|
1300 vs->write_pixels = vnc_write_pixels_copy; |
|
1301 vs->send_hextile_tile = send_hextile_tile_32; |
|
1302 } else |
|
1303 if (bits_per_pixel == 16 && |
|
1304 bits_per_pixel == vs->depth * 8 && |
|
1305 host_big_endian_flag == big_endian_flag && |
|
1306 red_max == 31 && green_max == 63 && blue_max == 31 && |
|
1307 red_shift == 11 && green_shift == 5 && blue_shift == 0) { |
|
1308 vs->depth = 2; |
|
1309 vs->write_pixels = vnc_write_pixels_copy; |
|
1310 vs->send_hextile_tile = send_hextile_tile_16; |
|
1311 } else |
|
1312 if (bits_per_pixel == 8 && |
|
1313 bits_per_pixel == vs->depth * 8 && |
|
1314 red_max == 7 && green_max == 7 && blue_max == 3 && |
|
1315 red_shift == 5 && green_shift == 2 && blue_shift == 0) { |
|
1316 vs->depth = 1; |
|
1317 vs->write_pixels = vnc_write_pixels_copy; |
|
1318 vs->send_hextile_tile = send_hextile_tile_8; |
|
1319 } else |
|
1320 { |
|
1321 /* generic and slower case */ |
|
1322 if (bits_per_pixel != 8 && |
|
1323 bits_per_pixel != 16 && |
|
1324 bits_per_pixel != 32) |
|
1325 goto fail; |
|
1326 if (vs->depth == 4) { |
|
1327 vs->send_hextile_tile = send_hextile_tile_generic_32; |
|
1328 } else if (vs->depth == 2) { |
|
1329 vs->send_hextile_tile = send_hextile_tile_generic_16; |
|
1330 } else { |
|
1331 vs->send_hextile_tile = send_hextile_tile_generic_8; |
|
1332 } |
|
1333 |
|
1334 vs->pix_big_endian = big_endian_flag; |
|
1335 vs->write_pixels = vnc_write_pixels_generic; |
|
1336 } |
|
1337 |
|
1338 vs->client_red_shift = red_shift; |
|
1339 vs->client_red_max = red_max; |
|
1340 vs->client_green_shift = green_shift; |
|
1341 vs->client_green_max = green_max; |
|
1342 vs->client_blue_shift = blue_shift; |
|
1343 vs->client_blue_max = blue_max; |
|
1344 vs->pix_bpp = bits_per_pixel / 8; |
|
1345 |
|
1346 #if 0 |
|
1347 DFG TODO |
|
1348 vga_hw_invalidate(); |
|
1349 vga_hw_update(); |
|
1350 #endif |
|
1351 } |
|
1352 |
|
1353 static void pixel_format_message (VncState *vs) { |
|
1354 char pad[3] = { 0, 0, 0 }; |
|
1355 |
|
1356 vnc_write_u8(vs, vs->depth * 8); /* bits-per-pixel */ |
|
1357 if (vs->depth == 4) vnc_write_u8(vs, 24); /* depth */ |
|
1358 else vnc_write_u8(vs, vs->depth * 8); /* depth */ |
|
1359 |
|
1360 #ifdef WORDS_BIGENDIAN |
|
1361 vnc_write_u8(vs, 1); /* big-endian-flag */ |
|
1362 #else |
|
1363 vnc_write_u8(vs, 0); /* big-endian-flag */ |
|
1364 #endif |
|
1365 vnc_write_u8(vs, 1); /* true-color-flag */ |
|
1366 if (vs->depth == 4) { |
|
1367 vnc_write_u16(vs, 0xFF); /* red-max */ |
|
1368 vnc_write_u16(vs, 0xFF); /* green-max */ |
|
1369 vnc_write_u16(vs, 0xFF); /* blue-max */ |
|
1370 vnc_write_u8(vs, 16); /* red-shift */ |
|
1371 vnc_write_u8(vs, 8); /* green-shift */ |
|
1372 vnc_write_u8(vs, 0); /* blue-shift */ |
|
1373 vs->send_hextile_tile = send_hextile_tile_32; |
|
1374 } else if (vs->depth == 2) { |
|
1375 vnc_write_u16(vs, 31); /* red-max */ |
|
1376 vnc_write_u16(vs, 63); /* green-max */ |
|
1377 vnc_write_u16(vs, 31); /* blue-max */ |
|
1378 vnc_write_u8(vs, 11); /* red-shift */ |
|
1379 vnc_write_u8(vs, 5); /* green-shift */ |
|
1380 vnc_write_u8(vs, 0); /* blue-shift */ |
|
1381 vs->send_hextile_tile = send_hextile_tile_16; |
|
1382 } else if (vs->depth == 1) { |
|
1383 /* XXX: change QEMU pixel 8 bit pixel format to match the VNC one ? */ |
|
1384 vnc_write_u16(vs, 7); /* red-max */ |
|
1385 vnc_write_u16(vs, 7); /* green-max */ |
|
1386 vnc_write_u16(vs, 3); /* blue-max */ |
|
1387 vnc_write_u8(vs, 5); /* red-shift */ |
|
1388 vnc_write_u8(vs, 2); /* green-shift */ |
|
1389 vnc_write_u8(vs, 0); /* blue-shift */ |
|
1390 vs->send_hextile_tile = send_hextile_tile_8; |
|
1391 } |
|
1392 vs->client_red_max = vs->server_red_max; |
|
1393 vs->client_green_max = vs->server_green_max; |
|
1394 vs->client_blue_max = vs->server_blue_max; |
|
1395 vs->client_red_shift = vs->server_red_shift; |
|
1396 vs->client_green_shift = vs->server_green_shift; |
|
1397 vs->client_blue_shift = vs->server_blue_shift; |
|
1398 vs->pix_bpp = vs->depth * 8; |
|
1399 vs->write_pixels = vnc_write_pixels_copy; |
|
1400 |
|
1401 vnc_write(vs, pad, 3); /* padding */ |
|
1402 } |
|
1403 |
|
1404 static void vnc_colordepth(DisplayState *ds, int depth) |
|
1405 { |
|
1406 int host_big_endian_flag; |
|
1407 struct VncState *vs = ds->opaque; |
|
1408 |
|
1409 switch (depth) { |
|
1410 case 24: |
|
1411 if (ds->depth == 32) return; |
|
1412 depth = 32; |
|
1413 break; |
|
1414 case 15: |
|
1415 case 8: |
|
1416 case 0: |
|
1417 return; |
|
1418 default: |
|
1419 break; |
|
1420 } |
|
1421 |
|
1422 #ifdef WORDS_BIGENDIAN |
|
1423 host_big_endian_flag = 1; |
|
1424 #else |
|
1425 host_big_endian_flag = 0; |
|
1426 #endif |
|
1427 |
|
1428 switch (depth) { |
|
1429 case 8: |
|
1430 vs->depth = depth / 8; |
|
1431 vs->server_red_max = 7; |
|
1432 vs->server_green_max = 7; |
|
1433 vs->server_blue_max = 3; |
|
1434 vs->server_red_shift = 5; |
|
1435 vs->server_green_shift = 2; |
|
1436 vs->server_blue_shift = 0; |
|
1437 break; |
|
1438 case 16: |
|
1439 vs->depth = depth / 8; |
|
1440 vs->server_red_max = 31; |
|
1441 vs->server_green_max = 63; |
|
1442 vs->server_blue_max = 31; |
|
1443 vs->server_red_shift = 11; |
|
1444 vs->server_green_shift = 5; |
|
1445 vs->server_blue_shift = 0; |
|
1446 break; |
|
1447 case 32: |
|
1448 vs->depth = 4; |
|
1449 vs->server_red_max = 255; |
|
1450 vs->server_green_max = 255; |
|
1451 vs->server_blue_max = 255; |
|
1452 vs->server_red_shift = 16; |
|
1453 vs->server_green_shift = 8; |
|
1454 vs->server_blue_shift = 0; |
|
1455 break; |
|
1456 default: |
|
1457 return; |
|
1458 } |
|
1459 |
|
1460 if (vs->csock != -1 && vs->has_WMVi) { |
|
1461 /* Sending a WMVi message to notify the client*/ |
|
1462 vnc_write_u8(vs, 0); /* msg id */ |
|
1463 vnc_write_u8(vs, 0); |
|
1464 vnc_write_u16(vs, 1); /* number of rects */ |
|
1465 vnc_framebuffer_update(vs, 0, 0, ds->width, ds->height, 0x574D5669); |
|
1466 pixel_format_message(vs); |
|
1467 vnc_flush(vs); |
|
1468 } else { |
|
1469 if (vs->pix_bpp == 4 && vs->depth == 4 && |
|
1470 host_big_endian_flag == vs->pix_big_endian && |
|
1471 vs->client_red_max == 0xff && vs->client_green_max == 0xff && vs->client_blue_max == 0xff && |
|
1472 vs->client_red_shift == 16 && vs->client_green_shift == 8 && vs->client_blue_shift == 0) { |
|
1473 vs->write_pixels = vnc_write_pixels_copy; |
|
1474 vs->send_hextile_tile = send_hextile_tile_32; |
|
1475 } else if (vs->pix_bpp == 2 && vs->depth == 2 && |
|
1476 host_big_endian_flag == vs->pix_big_endian && |
|
1477 vs->client_red_max == 31 && vs->client_green_max == 63 && vs->client_blue_max == 31 && |
|
1478 vs->client_red_shift == 11 && vs->client_green_shift == 5 && vs->client_blue_shift == 0) { |
|
1479 vs->write_pixels = vnc_write_pixels_copy; |
|
1480 vs->send_hextile_tile = send_hextile_tile_16; |
|
1481 } else if (vs->pix_bpp == 1 && vs->depth == 1 && |
|
1482 host_big_endian_flag == vs->pix_big_endian && |
|
1483 vs->client_red_max == 7 && vs->client_green_max == 7 && vs->client_blue_max == 3 && |
|
1484 vs->client_red_shift == 5 && vs->client_green_shift == 2 && vs->client_blue_shift == 0) { |
|
1485 vs->write_pixels = vnc_write_pixels_copy; |
|
1486 vs->send_hextile_tile = send_hextile_tile_8; |
|
1487 } else { |
|
1488 if (vs->depth == 4) { |
|
1489 vs->send_hextile_tile = send_hextile_tile_generic_32; |
|
1490 } else if (vs->depth == 2) { |
|
1491 vs->send_hextile_tile = send_hextile_tile_generic_16; |
|
1492 } else { |
|
1493 vs->send_hextile_tile = send_hextile_tile_generic_8; |
|
1494 } |
|
1495 vs->write_pixels = vnc_write_pixels_generic; |
|
1496 } |
|
1497 } |
|
1498 } |
|
1499 |
|
1500 static int protocol_client_msg(VncState *vs, uint8_t *data, size_t len) |
|
1501 { |
|
1502 int i; |
|
1503 uint16_t limit; |
|
1504 |
|
1505 switch (data[0]) { |
|
1506 case 0: |
|
1507 if (len == 1) |
|
1508 return 20; |
|
1509 |
|
1510 set_pixel_format(vs, read_u8(data, 4), read_u8(data, 5), |
|
1511 read_u8(data, 6), read_u8(data, 7), |
|
1512 read_u16(data, 8), read_u16(data, 10), |
|
1513 read_u16(data, 12), read_u8(data, 14), |
|
1514 read_u8(data, 15), read_u8(data, 16)); |
|
1515 break; |
|
1516 case 2: |
|
1517 if (len == 1) |
|
1518 return 4; |
|
1519 |
|
1520 if (len == 4) { |
|
1521 limit = read_u16(data, 2); |
|
1522 if (limit > 0) |
|
1523 return 4 + (limit * 4); |
|
1524 } else |
|
1525 limit = read_u16(data, 2); |
|
1526 |
|
1527 for (i = 0; i < limit; i++) { |
|
1528 int32_t val = read_s32(data, 4 + (i * 4)); |
|
1529 memcpy(data + 4 + (i * 4), &val, sizeof(val)); |
|
1530 } |
|
1531 |
|
1532 set_encodings(vs, (int32_t *)(data + 4), limit); |
|
1533 break; |
|
1534 case 3: |
|
1535 if (len == 1) |
|
1536 return 10; |
|
1537 |
|
1538 framebuffer_update_request(vs, |
|
1539 read_u8(data, 1), read_u16(data, 2), read_u16(data, 4), |
|
1540 read_u16(data, 6), read_u16(data, 8)); |
|
1541 break; |
|
1542 case 4: |
|
1543 if (len == 1) |
|
1544 return 8; |
|
1545 |
|
1546 key_event(vs, read_u8(data, 1), read_u32(data, 4)); |
|
1547 break; |
|
1548 case 5: |
|
1549 if (len == 1) |
|
1550 return 6; |
|
1551 |
|
1552 pointer_event(vs, read_u8(data, 1), read_u16(data, 2), read_u16(data, 4)); |
|
1553 break; |
|
1554 case 6: |
|
1555 if (len == 1) |
|
1556 return 8; |
|
1557 |
|
1558 if (len == 8) { |
|
1559 uint32_t dlen = read_u32(data, 4); |
|
1560 if (dlen > 0) |
|
1561 return 8 + dlen; |
|
1562 } |
|
1563 |
|
1564 client_cut_text(vs, read_u32(data, 4), data + 8); |
|
1565 break; |
|
1566 case 255: |
|
1567 if (len == 1) |
|
1568 return 2; |
|
1569 |
|
1570 switch (read_u8(data, 1)) { |
|
1571 case 0: |
|
1572 if (len == 2) |
|
1573 return 12; |
|
1574 |
|
1575 ext_key_event(vs, read_u16(data, 2), |
|
1576 read_u32(data, 4), read_u32(data, 8)); |
|
1577 break; |
|
1578 case 1: |
|
1579 if (len == 2) |
|
1580 return 4; |
|
1581 |
|
1582 switch (read_u16 (data, 2)) { |
|
1583 case 0: |
|
1584 audio_add(vs); |
|
1585 break; |
|
1586 case 1: |
|
1587 audio_del(vs); |
|
1588 break; |
|
1589 case 2: |
|
1590 if (len == 4) |
|
1591 return 10; |
|
1592 switch (read_u8(data, 4)) { |
|
1593 case 0: vs->as.fmt = AUD_FMT_U8; break; |
|
1594 case 1: vs->as.fmt = AUD_FMT_S8; break; |
|
1595 case 2: vs->as.fmt = AUD_FMT_U16; break; |
|
1596 case 3: vs->as.fmt = AUD_FMT_S16; break; |
|
1597 case 4: vs->as.fmt = AUD_FMT_U32; break; |
|
1598 case 5: vs->as.fmt = AUD_FMT_S32; break; |
|
1599 default: |
|
1600 printf("Invalid audio format %d\n", read_u8(data, 4)); |
|
1601 vnc_client_error(vs); |
|
1602 break; |
|
1603 } |
|
1604 vs->as.nchannels = read_u8(data, 5); |
|
1605 if (vs->as.nchannels != 1 && vs->as.nchannels != 2) { |
|
1606 printf("Invalid audio channel coount %d\n", |
|
1607 read_u8(data, 5)); |
|
1608 vnc_client_error(vs); |
|
1609 break; |
|
1610 } |
|
1611 vs->as.freq = read_u32(data, 6); |
|
1612 break; |
|
1613 default: |
|
1614 printf ("Invalid audio message %d\n", read_u8(data, 4)); |
|
1615 vnc_client_error(vs); |
|
1616 break; |
|
1617 } |
|
1618 break; |
|
1619 |
|
1620 default: |
|
1621 printf("Msg: %d\n", read_u16(data, 0)); |
|
1622 vnc_client_error(vs); |
|
1623 break; |
|
1624 } |
|
1625 break; |
|
1626 default: |
|
1627 printf("Msg: %d\n", data[0]); |
|
1628 vnc_client_error(vs); |
|
1629 break; |
|
1630 } |
|
1631 |
|
1632 vnc_read_when(vs, protocol_client_msg, 1); |
|
1633 return 0; |
|
1634 } |
|
1635 |
|
1636 static int protocol_client_init(VncState *vs, uint8_t *data, size_t len) |
|
1637 { |
|
1638 char buf[1024]; |
|
1639 int size; |
|
1640 |
|
1641 vs->width = ds_get_width(vs->ds); |
|
1642 vs->height = ds_get_height(vs->ds); |
|
1643 vnc_write_u16(vs, ds_get_width(vs->ds)); |
|
1644 vnc_write_u16(vs, ds_get_height(vs->ds)); |
|
1645 |
|
1646 pixel_format_message(vs); |
|
1647 |
|
1648 if (qemu_name) |
|
1649 size = snprintf(buf, sizeof(buf), "QEMU (%s)", qemu_name); |
|
1650 else |
|
1651 size = snprintf(buf, sizeof(buf), "QEMU"); |
|
1652 |
|
1653 vnc_write_u32(vs, size); |
|
1654 vnc_write(vs, buf, size); |
|
1655 vnc_flush(vs); |
|
1656 |
|
1657 vnc_read_when(vs, protocol_client_msg, 1); |
|
1658 |
|
1659 return 0; |
|
1660 } |
|
1661 |
|
1662 static void make_challenge(VncState *vs) |
|
1663 { |
|
1664 int i; |
|
1665 |
|
1666 srand(time(NULL)+getpid()+getpid()*987654+rand()); |
|
1667 |
|
1668 for (i = 0 ; i < sizeof(vs->challenge) ; i++) |
|
1669 vs->challenge[i] = (int) (256.0*rand()/(RAND_MAX+1.0)); |
|
1670 } |
|
1671 |
|
1672 static int protocol_client_auth_vnc(VncState *vs, uint8_t *data, size_t len) |
|
1673 { |
|
1674 unsigned char response[VNC_AUTH_CHALLENGE_SIZE]; |
|
1675 int i, j, pwlen; |
|
1676 unsigned char key[8]; |
|
1677 |
|
1678 if (!vs->password || !vs->password[0]) { |
|
1679 VNC_DEBUG("No password configured on server"); |
|
1680 vnc_write_u32(vs, 1); /* Reject auth */ |
|
1681 if (vs->minor >= 8) { |
|
1682 static const char err[] = "Authentication failed"; |
|
1683 vnc_write_u32(vs, sizeof(err)); |
|
1684 vnc_write(vs, err, sizeof(err)); |
|
1685 } |
|
1686 vnc_flush(vs); |
|
1687 vnc_client_error(vs); |
|
1688 return 0; |
|
1689 } |
|
1690 |
|
1691 memcpy(response, vs->challenge, VNC_AUTH_CHALLENGE_SIZE); |
|
1692 |
|
1693 /* Calculate the expected challenge response */ |
|
1694 pwlen = strlen(vs->password); |
|
1695 for (i=0; i<sizeof(key); i++) |
|
1696 key[i] = i<pwlen ? vs->password[i] : 0; |
|
1697 deskey(key, EN0); |
|
1698 for (j = 0; j < VNC_AUTH_CHALLENGE_SIZE; j += 8) |
|
1699 des(response+j, response+j); |
|
1700 |
|
1701 /* Compare expected vs actual challenge response */ |
|
1702 if (memcmp(response, data, VNC_AUTH_CHALLENGE_SIZE) != 0) { |
|
1703 VNC_DEBUG("Client challenge reponse did not match\n"); |
|
1704 vnc_write_u32(vs, 1); /* Reject auth */ |
|
1705 if (vs->minor >= 8) { |
|
1706 static const char err[] = "Authentication failed"; |
|
1707 vnc_write_u32(vs, sizeof(err)); |
|
1708 vnc_write(vs, err, sizeof(err)); |
|
1709 } |
|
1710 vnc_flush(vs); |
|
1711 vnc_client_error(vs); |
|
1712 } else { |
|
1713 VNC_DEBUG("Accepting VNC challenge response\n"); |
|
1714 vnc_write_u32(vs, 0); /* Accept auth */ |
|
1715 vnc_flush(vs); |
|
1716 |
|
1717 vnc_read_when(vs, protocol_client_init, 1); |
|
1718 } |
|
1719 return 0; |
|
1720 } |
|
1721 |
|
1722 static int start_auth_vnc(VncState *vs) |
|
1723 { |
|
1724 make_challenge(vs); |
|
1725 /* Send client a 'random' challenge */ |
|
1726 vnc_write(vs, vs->challenge, sizeof(vs->challenge)); |
|
1727 vnc_flush(vs); |
|
1728 |
|
1729 vnc_read_when(vs, protocol_client_auth_vnc, sizeof(vs->challenge)); |
|
1730 return 0; |
|
1731 } |
|
1732 |
|
1733 |
|
1734 #ifdef CONFIG_VNC_TLS |
|
1735 #define DH_BITS 1024 |
|
1736 static gnutls_dh_params_t dh_params; |
|
1737 |
|
1738 static int vnc_tls_initialize(void) |
|
1739 { |
|
1740 static int tlsinitialized = 0; |
|
1741 |
|
1742 if (tlsinitialized) |
|
1743 return 1; |
|
1744 |
|
1745 if (gnutls_global_init () < 0) |
|
1746 return 0; |
|
1747 |
|
1748 /* XXX ought to re-generate diffie-hellmen params periodically */ |
|
1749 if (gnutls_dh_params_init (&dh_params) < 0) |
|
1750 return 0; |
|
1751 if (gnutls_dh_params_generate2 (dh_params, DH_BITS) < 0) |
|
1752 return 0; |
|
1753 |
|
1754 #if defined(_VNC_DEBUG) && _VNC_DEBUG >= 2 |
|
1755 gnutls_global_set_log_level(10); |
|
1756 gnutls_global_set_log_function(vnc_debug_gnutls_log); |
|
1757 #endif |
|
1758 |
|
1759 tlsinitialized = 1; |
|
1760 |
|
1761 return 1; |
|
1762 } |
|
1763 |
|
1764 static gnutls_anon_server_credentials vnc_tls_initialize_anon_cred(void) |
|
1765 { |
|
1766 gnutls_anon_server_credentials anon_cred; |
|
1767 int ret; |
|
1768 |
|
1769 if ((ret = gnutls_anon_allocate_server_credentials(&anon_cred)) < 0) { |
|
1770 VNC_DEBUG("Cannot allocate credentials %s\n", gnutls_strerror(ret)); |
|
1771 return NULL; |
|
1772 } |
|
1773 |
|
1774 gnutls_anon_set_server_dh_params(anon_cred, dh_params); |
|
1775 |
|
1776 return anon_cred; |
|
1777 } |
|
1778 |
|
1779 |
|
1780 static gnutls_certificate_credentials_t vnc_tls_initialize_x509_cred(VncState *vs) |
|
1781 { |
|
1782 gnutls_certificate_credentials_t x509_cred; |
|
1783 int ret; |
|
1784 |
|
1785 if (!vs->x509cacert) { |
|
1786 VNC_DEBUG("No CA x509 certificate specified\n"); |
|
1787 return NULL; |
|
1788 } |
|
1789 if (!vs->x509cert) { |
|
1790 VNC_DEBUG("No server x509 certificate specified\n"); |
|
1791 return NULL; |
|
1792 } |
|
1793 if (!vs->x509key) { |
|
1794 VNC_DEBUG("No server private key specified\n"); |
|
1795 return NULL; |
|
1796 } |
|
1797 |
|
1798 if ((ret = gnutls_certificate_allocate_credentials(&x509_cred)) < 0) { |
|
1799 VNC_DEBUG("Cannot allocate credentials %s\n", gnutls_strerror(ret)); |
|
1800 return NULL; |
|
1801 } |
|
1802 if ((ret = gnutls_certificate_set_x509_trust_file(x509_cred, |
|
1803 vs->x509cacert, |
|
1804 GNUTLS_X509_FMT_PEM)) < 0) { |
|
1805 VNC_DEBUG("Cannot load CA certificate %s\n", gnutls_strerror(ret)); |
|
1806 gnutls_certificate_free_credentials(x509_cred); |
|
1807 return NULL; |
|
1808 } |
|
1809 |
|
1810 if ((ret = gnutls_certificate_set_x509_key_file (x509_cred, |
|
1811 vs->x509cert, |
|
1812 vs->x509key, |
|
1813 GNUTLS_X509_FMT_PEM)) < 0) { |
|
1814 VNC_DEBUG("Cannot load certificate & key %s\n", gnutls_strerror(ret)); |
|
1815 gnutls_certificate_free_credentials(x509_cred); |
|
1816 return NULL; |
|
1817 } |
|
1818 |
|
1819 if (vs->x509cacrl) { |
|
1820 if ((ret = gnutls_certificate_set_x509_crl_file(x509_cred, |
|
1821 vs->x509cacrl, |
|
1822 GNUTLS_X509_FMT_PEM)) < 0) { |
|
1823 VNC_DEBUG("Cannot load CRL %s\n", gnutls_strerror(ret)); |
|
1824 gnutls_certificate_free_credentials(x509_cred); |
|
1825 return NULL; |
|
1826 } |
|
1827 } |
|
1828 |
|
1829 gnutls_certificate_set_dh_params (x509_cred, dh_params); |
|
1830 |
|
1831 return x509_cred; |
|
1832 } |
|
1833 |
|
1834 static int vnc_validate_certificate(struct VncState *vs) |
|
1835 { |
|
1836 int ret; |
|
1837 unsigned int status; |
|
1838 const gnutls_datum_t *certs; |
|
1839 unsigned int nCerts, i; |
|
1840 time_t now; |
|
1841 |
|
1842 VNC_DEBUG("Validating client certificate\n"); |
|
1843 if ((ret = gnutls_certificate_verify_peers2 (vs->tls_session, &status)) < 0) { |
|
1844 VNC_DEBUG("Verify failed %s\n", gnutls_strerror(ret)); |
|
1845 return -1; |
|
1846 } |
|
1847 |
|
1848 if ((now = time(NULL)) == ((time_t)-1)) { |
|
1849 return -1; |
|
1850 } |
|
1851 |
|
1852 if (status != 0) { |
|
1853 if (status & GNUTLS_CERT_INVALID) |
|
1854 VNC_DEBUG("The certificate is not trusted.\n"); |
|
1855 |
|
1856 if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) |
|
1857 VNC_DEBUG("The certificate hasn't got a known issuer.\n"); |
|
1858 |
|
1859 if (status & GNUTLS_CERT_REVOKED) |
|
1860 VNC_DEBUG("The certificate has been revoked.\n"); |
|
1861 |
|
1862 if (status & GNUTLS_CERT_INSECURE_ALGORITHM) |
|
1863 VNC_DEBUG("The certificate uses an insecure algorithm\n"); |
|
1864 |
|
1865 return -1; |
|
1866 } else { |
|
1867 VNC_DEBUG("Certificate is valid!\n"); |
|
1868 } |
|
1869 |
|
1870 /* Only support x509 for now */ |
|
1871 if (gnutls_certificate_type_get(vs->tls_session) != GNUTLS_CRT_X509) |
|
1872 return -1; |
|
1873 |
|
1874 if (!(certs = gnutls_certificate_get_peers(vs->tls_session, &nCerts))) |
|
1875 return -1; |
|
1876 |
|
1877 for (i = 0 ; i < nCerts ; i++) { |
|
1878 gnutls_x509_crt_t cert; |
|
1879 VNC_DEBUG ("Checking certificate chain %d\n", i); |
|
1880 if (gnutls_x509_crt_init (&cert) < 0) |
|
1881 return -1; |
|
1882 |
|
1883 if (gnutls_x509_crt_import(cert, &certs[i], GNUTLS_X509_FMT_DER) < 0) { |
|
1884 gnutls_x509_crt_deinit (cert); |
|
1885 return -1; |
|
1886 } |
|
1887 |
|
1888 if (gnutls_x509_crt_get_expiration_time (cert) < now) { |
|
1889 VNC_DEBUG("The certificate has expired\n"); |
|
1890 gnutls_x509_crt_deinit (cert); |
|
1891 return -1; |
|
1892 } |
|
1893 |
|
1894 if (gnutls_x509_crt_get_activation_time (cert) > now) { |
|
1895 VNC_DEBUG("The certificate is not yet activated\n"); |
|
1896 gnutls_x509_crt_deinit (cert); |
|
1897 return -1; |
|
1898 } |
|
1899 |
|
1900 if (gnutls_x509_crt_get_activation_time (cert) > now) { |
|
1901 VNC_DEBUG("The certificate is not yet activated\n"); |
|
1902 gnutls_x509_crt_deinit (cert); |
|
1903 return -1; |
|
1904 } |
|
1905 |
|
1906 gnutls_x509_crt_deinit (cert); |
|
1907 } |
|
1908 |
|
1909 return 0; |
|
1910 } |
|
1911 |
|
1912 |
|
1913 static int start_auth_vencrypt_subauth(VncState *vs) |
|
1914 { |
|
1915 switch (vs->subauth) { |
|
1916 case VNC_AUTH_VENCRYPT_TLSNONE: |
|
1917 case VNC_AUTH_VENCRYPT_X509NONE: |
|
1918 VNC_DEBUG("Accept TLS auth none\n"); |
|
1919 vnc_write_u32(vs, 0); /* Accept auth completion */ |
|
1920 vnc_read_when(vs, protocol_client_init, 1); |
|
1921 break; |
|
1922 |
|
1923 case VNC_AUTH_VENCRYPT_TLSVNC: |
|
1924 case VNC_AUTH_VENCRYPT_X509VNC: |
|
1925 VNC_DEBUG("Start TLS auth VNC\n"); |
|
1926 return start_auth_vnc(vs); |
|
1927 |
|
1928 default: /* Should not be possible, but just in case */ |
|
1929 VNC_DEBUG("Reject auth %d\n", vs->auth); |
|
1930 vnc_write_u8(vs, 1); |
|
1931 if (vs->minor >= 8) { |
|
1932 static const char err[] = "Unsupported authentication type"; |
|
1933 vnc_write_u32(vs, sizeof(err)); |
|
1934 vnc_write(vs, err, sizeof(err)); |
|
1935 } |
|
1936 vnc_client_error(vs); |
|
1937 } |
|
1938 |
|
1939 return 0; |
|
1940 } |
|
1941 |
|
1942 static void vnc_handshake_io(void *opaque); |
|
1943 |
|
1944 static int vnc_continue_handshake(struct VncState *vs) { |
|
1945 int ret; |
|
1946 |
|
1947 if ((ret = gnutls_handshake(vs->tls_session)) < 0) { |
|
1948 if (!gnutls_error_is_fatal(ret)) { |
|
1949 VNC_DEBUG("Handshake interrupted (blocking)\n"); |
|
1950 if (!gnutls_record_get_direction(vs->tls_session)) |
|
1951 qemu_set_fd_handler(vs->csock, vnc_handshake_io, NULL, vs); |
|
1952 else |
|
1953 qemu_set_fd_handler(vs->csock, NULL, vnc_handshake_io, vs); |
|
1954 return 0; |
|
1955 } |
|
1956 VNC_DEBUG("Handshake failed %s\n", gnutls_strerror(ret)); |
|
1957 vnc_client_error(vs); |
|
1958 return -1; |
|
1959 } |
|
1960 |
|
1961 if (vs->x509verify) { |
|
1962 if (vnc_validate_certificate(vs) < 0) { |
|
1963 VNC_DEBUG("Client verification failed\n"); |
|
1964 vnc_client_error(vs); |
|
1965 return -1; |
|
1966 } else { |
|
1967 VNC_DEBUG("Client verification passed\n"); |
|
1968 } |
|
1969 } |
|
1970 |
|
1971 VNC_DEBUG("Handshake done, switching to TLS data mode\n"); |
|
1972 vs->wiremode = VNC_WIREMODE_TLS; |
|
1973 qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, vnc_client_write, vs); |
|
1974 |
|
1975 return start_auth_vencrypt_subauth(vs); |
|
1976 } |
|
1977 |
|
1978 static void vnc_handshake_io(void *opaque) { |
|
1979 struct VncState *vs = (struct VncState *)opaque; |
|
1980 |
|
1981 VNC_DEBUG("Handshake IO continue\n"); |
|
1982 vnc_continue_handshake(vs); |
|
1983 } |
|
1984 |
|
1985 #define NEED_X509_AUTH(vs) \ |
|
1986 ((vs)->subauth == VNC_AUTH_VENCRYPT_X509NONE || \ |
|
1987 (vs)->subauth == VNC_AUTH_VENCRYPT_X509VNC || \ |
|
1988 (vs)->subauth == VNC_AUTH_VENCRYPT_X509PLAIN) |
|
1989 |
|
1990 |
|
1991 static int vnc_start_tls(struct VncState *vs) { |
|
1992 static const int cert_type_priority[] = { GNUTLS_CRT_X509, 0 }; |
|
1993 static const int protocol_priority[]= { GNUTLS_TLS1_1, GNUTLS_TLS1_0, GNUTLS_SSL3, 0 }; |
|
1994 static const int kx_anon[] = {GNUTLS_KX_ANON_DH, 0}; |
|
1995 static const int kx_x509[] = {GNUTLS_KX_DHE_DSS, GNUTLS_KX_RSA, GNUTLS_KX_DHE_RSA, GNUTLS_KX_SRP, 0}; |
|
1996 |
|
1997 VNC_DEBUG("Do TLS setup\n"); |
|
1998 if (vnc_tls_initialize() < 0) { |
|
1999 VNC_DEBUG("Failed to init TLS\n"); |
|
2000 vnc_client_error(vs); |
|
2001 return -1; |
|
2002 } |
|
2003 if (vs->tls_session == NULL) { |
|
2004 if (gnutls_init(&vs->tls_session, GNUTLS_SERVER) < 0) { |
|
2005 vnc_client_error(vs); |
|
2006 return -1; |
|
2007 } |
|
2008 |
|
2009 if (gnutls_set_default_priority(vs->tls_session) < 0) { |
|
2010 gnutls_deinit(vs->tls_session); |
|
2011 vs->tls_session = NULL; |
|
2012 vnc_client_error(vs); |
|
2013 return -1; |
|
2014 } |
|
2015 |
|
2016 if (gnutls_kx_set_priority(vs->tls_session, NEED_X509_AUTH(vs) ? kx_x509 : kx_anon) < 0) { |
|
2017 gnutls_deinit(vs->tls_session); |
|
2018 vs->tls_session = NULL; |
|
2019 vnc_client_error(vs); |
|
2020 return -1; |
|
2021 } |
|
2022 |
|
2023 if (gnutls_certificate_type_set_priority(vs->tls_session, cert_type_priority) < 0) { |
|
2024 gnutls_deinit(vs->tls_session); |
|
2025 vs->tls_session = NULL; |
|
2026 vnc_client_error(vs); |
|
2027 return -1; |
|
2028 } |
|
2029 |
|
2030 if (gnutls_protocol_set_priority(vs->tls_session, protocol_priority) < 0) { |
|
2031 gnutls_deinit(vs->tls_session); |
|
2032 vs->tls_session = NULL; |
|
2033 vnc_client_error(vs); |
|
2034 return -1; |
|
2035 } |
|
2036 |
|
2037 if (NEED_X509_AUTH(vs)) { |
|
2038 gnutls_certificate_server_credentials x509_cred = vnc_tls_initialize_x509_cred(vs); |
|
2039 if (!x509_cred) { |
|
2040 gnutls_deinit(vs->tls_session); |
|
2041 vs->tls_session = NULL; |
|
2042 vnc_client_error(vs); |
|
2043 return -1; |
|
2044 } |
|
2045 if (gnutls_credentials_set(vs->tls_session, GNUTLS_CRD_CERTIFICATE, x509_cred) < 0) { |
|
2046 gnutls_deinit(vs->tls_session); |
|
2047 vs->tls_session = NULL; |
|
2048 gnutls_certificate_free_credentials(x509_cred); |
|
2049 vnc_client_error(vs); |
|
2050 return -1; |
|
2051 } |
|
2052 if (vs->x509verify) { |
|
2053 VNC_DEBUG("Requesting a client certificate\n"); |
|
2054 gnutls_certificate_server_set_request (vs->tls_session, GNUTLS_CERT_REQUEST); |
|
2055 } |
|
2056 |
|
2057 } else { |
|
2058 gnutls_anon_server_credentials anon_cred = vnc_tls_initialize_anon_cred(); |
|
2059 if (!anon_cred) { |
|
2060 gnutls_deinit(vs->tls_session); |
|
2061 vs->tls_session = NULL; |
|
2062 vnc_client_error(vs); |
|
2063 return -1; |
|
2064 } |
|
2065 if (gnutls_credentials_set(vs->tls_session, GNUTLS_CRD_ANON, anon_cred) < 0) { |
|
2066 gnutls_deinit(vs->tls_session); |
|
2067 vs->tls_session = NULL; |
|
2068 gnutls_anon_free_server_credentials(anon_cred); |
|
2069 vnc_client_error(vs); |
|
2070 return -1; |
|
2071 } |
|
2072 } |
|
2073 |
|
2074 gnutls_transport_set_ptr(vs->tls_session, (gnutls_transport_ptr_t)vs); |
|
2075 gnutls_transport_set_push_function(vs->tls_session, vnc_tls_push); |
|
2076 gnutls_transport_set_pull_function(vs->tls_session, vnc_tls_pull); |
|
2077 } |
|
2078 |
|
2079 VNC_DEBUG("Start TLS handshake process\n"); |
|
2080 return vnc_continue_handshake(vs); |
|
2081 } |
|
2082 |
|
2083 static int protocol_client_vencrypt_auth(VncState *vs, uint8_t *data, size_t len) |
|
2084 { |
|
2085 int auth = read_u32(data, 0); |
|
2086 |
|
2087 if (auth != vs->subauth) { |
|
2088 VNC_DEBUG("Rejecting auth %d\n", auth); |
|
2089 vnc_write_u8(vs, 0); /* Reject auth */ |
|
2090 vnc_flush(vs); |
|
2091 vnc_client_error(vs); |
|
2092 } else { |
|
2093 VNC_DEBUG("Accepting auth %d, starting handshake\n", auth); |
|
2094 vnc_write_u8(vs, 1); /* Accept auth */ |
|
2095 vnc_flush(vs); |
|
2096 |
|
2097 if (vnc_start_tls(vs) < 0) { |
|
2098 VNC_DEBUG("Failed to complete TLS\n"); |
|
2099 return 0; |
|
2100 } |
|
2101 |
|
2102 if (vs->wiremode == VNC_WIREMODE_TLS) { |
|
2103 VNC_DEBUG("Starting VeNCrypt subauth\n"); |
|
2104 return start_auth_vencrypt_subauth(vs); |
|
2105 } else { |
|
2106 VNC_DEBUG("TLS handshake blocked\n"); |
|
2107 return 0; |
|
2108 } |
|
2109 } |
|
2110 return 0; |
|
2111 } |
|
2112 |
|
2113 static int protocol_client_vencrypt_init(VncState *vs, uint8_t *data, size_t len) |
|
2114 { |
|
2115 if (data[0] != 0 || |
|
2116 data[1] != 2) { |
|
2117 VNC_DEBUG("Unsupported VeNCrypt protocol %d.%d\n", (int)data[0], (int)data[1]); |
|
2118 vnc_write_u8(vs, 1); /* Reject version */ |
|
2119 vnc_flush(vs); |
|
2120 vnc_client_error(vs); |
|
2121 } else { |
|
2122 VNC_DEBUG("Sending allowed auth %d\n", vs->subauth); |
|
2123 vnc_write_u8(vs, 0); /* Accept version */ |
|
2124 vnc_write_u8(vs, 1); /* Number of sub-auths */ |
|
2125 vnc_write_u32(vs, vs->subauth); /* The supported auth */ |
|
2126 vnc_flush(vs); |
|
2127 vnc_read_when(vs, protocol_client_vencrypt_auth, 4); |
|
2128 } |
|
2129 return 0; |
|
2130 } |
|
2131 |
|
2132 static int start_auth_vencrypt(VncState *vs) |
|
2133 { |
|
2134 /* Send VeNCrypt version 0.2 */ |
|
2135 vnc_write_u8(vs, 0); |
|
2136 vnc_write_u8(vs, 2); |
|
2137 |
|
2138 vnc_read_when(vs, protocol_client_vencrypt_init, 2); |
|
2139 return 0; |
|
2140 } |
|
2141 #endif /* CONFIG_VNC_TLS */ |
|
2142 |
|
2143 static int protocol_client_auth(VncState *vs, uint8_t *data, size_t len) |
|
2144 { |
|
2145 /* We only advertise 1 auth scheme at a time, so client |
|
2146 * must pick the one we sent. Verify this */ |
|
2147 if (data[0] != vs->auth) { /* Reject auth */ |
|
2148 VNC_DEBUG("Reject auth %d\n", (int)data[0]); |
|
2149 vnc_write_u32(vs, 1); |
|
2150 if (vs->minor >= 8) { |
|
2151 static const char err[] = "Authentication failed"; |
|
2152 vnc_write_u32(vs, sizeof(err)); |
|
2153 vnc_write(vs, err, sizeof(err)); |
|
2154 } |
|
2155 vnc_client_error(vs); |
|
2156 } else { /* Accept requested auth */ |
|
2157 VNC_DEBUG("Client requested auth %d\n", (int)data[0]); |
|
2158 switch (vs->auth) { |
|
2159 case VNC_AUTH_NONE: |
|
2160 VNC_DEBUG("Accept auth none\n"); |
|
2161 if (vs->minor >= 8) { |
|
2162 vnc_write_u32(vs, 0); /* Accept auth completion */ |
|
2163 vnc_flush(vs); |
|
2164 } |
|
2165 vnc_read_when(vs, protocol_client_init, 1); |
|
2166 break; |
|
2167 |
|
2168 case VNC_AUTH_VNC: |
|
2169 VNC_DEBUG("Start VNC auth\n"); |
|
2170 return start_auth_vnc(vs); |
|
2171 |
|
2172 #ifdef CONFIG_VNC_TLS |
|
2173 case VNC_AUTH_VENCRYPT: |
|
2174 VNC_DEBUG("Accept VeNCrypt auth\n");; |
|
2175 return start_auth_vencrypt(vs); |
|
2176 #endif /* CONFIG_VNC_TLS */ |
|
2177 |
|
2178 default: /* Should not be possible, but just in case */ |
|
2179 VNC_DEBUG("Reject auth %d\n", vs->auth); |
|
2180 vnc_write_u8(vs, 1); |
|
2181 if (vs->minor >= 8) { |
|
2182 static const char err[] = "Authentication failed"; |
|
2183 vnc_write_u32(vs, sizeof(err)); |
|
2184 vnc_write(vs, err, sizeof(err)); |
|
2185 } |
|
2186 vnc_client_error(vs); |
|
2187 } |
|
2188 } |
|
2189 return 0; |
|
2190 } |
|
2191 |
|
2192 static int protocol_version(VncState *vs, uint8_t *version, size_t len) |
|
2193 { |
|
2194 char local[13]; |
|
2195 |
|
2196 memcpy(local, version, 12); |
|
2197 local[12] = 0; |
|
2198 |
|
2199 if (sscanf(local, "RFB %03d.%03d\n", &vs->major, &vs->minor) != 2) { |
|
2200 VNC_DEBUG("Malformed protocol version %s\n", local); |
|
2201 vnc_client_error(vs); |
|
2202 return 0; |
|
2203 } |
|
2204 VNC_DEBUG("Client request protocol version %d.%d\n", vs->major, vs->minor); |
|
2205 if (vs->major != 3 || |
|
2206 (vs->minor != 3 && |
|
2207 vs->minor != 4 && |
|
2208 vs->minor != 5 && |
|
2209 vs->minor != 7 && |
|
2210 vs->minor != 8)) { |
|
2211 VNC_DEBUG("Unsupported client version\n"); |
|
2212 vnc_write_u32(vs, VNC_AUTH_INVALID); |
|
2213 vnc_flush(vs); |
|
2214 vnc_client_error(vs); |
|
2215 return 0; |
|
2216 } |
|
2217 /* Some broken clients report v3.4 or v3.5, which spec requires to be treated |
|
2218 * as equivalent to v3.3 by servers |
|
2219 */ |
|
2220 if (vs->minor == 4 || vs->minor == 5) |
|
2221 vs->minor = 3; |
|
2222 |
|
2223 if (vs->minor == 3) { |
|
2224 if (vs->auth == VNC_AUTH_NONE) { |
|
2225 VNC_DEBUG("Tell client auth none\n"); |
|
2226 vnc_write_u32(vs, vs->auth); |
|
2227 vnc_flush(vs); |
|
2228 vnc_read_when(vs, protocol_client_init, 1); |
|
2229 } else if (vs->auth == VNC_AUTH_VNC) { |
|
2230 VNC_DEBUG("Tell client VNC auth\n"); |
|
2231 vnc_write_u32(vs, vs->auth); |
|
2232 vnc_flush(vs); |
|
2233 start_auth_vnc(vs); |
|
2234 } else { |
|
2235 VNC_DEBUG("Unsupported auth %d for protocol 3.3\n", vs->auth); |
|
2236 vnc_write_u32(vs, VNC_AUTH_INVALID); |
|
2237 vnc_flush(vs); |
|
2238 vnc_client_error(vs); |
|
2239 } |
|
2240 } else { |
|
2241 VNC_DEBUG("Telling client we support auth %d\n", vs->auth); |
|
2242 vnc_write_u8(vs, 1); /* num auth */ |
|
2243 vnc_write_u8(vs, vs->auth); |
|
2244 vnc_read_when(vs, protocol_client_auth, 1); |
|
2245 vnc_flush(vs); |
|
2246 } |
|
2247 |
|
2248 return 0; |
|
2249 } |
|
2250 |
|
2251 static void vnc_connect(VncState *vs) |
|
2252 { |
|
2253 VNC_DEBUG("New client on socket %d\n", vs->csock); |
|
2254 gui_notify_idle(0); |
|
2255 /*vs->ds->idle = 0;*/ |
|
2256 socket_set_nonblock(vs->csock); |
|
2257 qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs); |
|
2258 vnc_write(vs, "RFB 003.008\n", 12); |
|
2259 vnc_flush(vs); |
|
2260 vnc_read_when(vs, protocol_version, 12); |
|
2261 memset(vs->old_data, 0, ds_get_linesize(vs->ds) * ds_get_height(vs->ds)); |
|
2262 memset(vs->dirty_row, 0xFF, sizeof(vs->dirty_row)); |
|
2263 vs->has_resize = 0; |
|
2264 vs->has_hextile = 0; |
|
2265 vs->ds->dpy_copy = NULL; |
|
2266 vnc_update_client(vs); |
|
2267 reset_keys(vs); |
|
2268 } |
|
2269 |
|
2270 static void vnc_listen_read(void *opaque) |
|
2271 { |
|
2272 VncState *vs = opaque; |
|
2273 struct sockaddr_in addr; |
|
2274 socklen_t addrlen = sizeof(addr); |
|
2275 |
|
2276 /* Catch-up */ |
|
2277 #if 0 |
|
2278 DFG TODO |
|
2279 vga_hw_update(); |
|
2280 #endif |
|
2281 |
|
2282 vs->csock = accept(vs->lsock, (struct sockaddr *)&addr, &addrlen); |
|
2283 if (vs->csock != -1) { |
|
2284 vnc_connect(vs); |
|
2285 } |
|
2286 } |
|
2287 |
|
2288 void vnc_display_init(DisplayState *ds) |
|
2289 { |
|
2290 VncState *vs; |
|
2291 |
|
2292 vs = qemu_mallocz(sizeof(VncState)); |
|
2293 if (!vs) |
|
2294 exit(1); |
|
2295 |
|
2296 ds->opaque = vs; |
|
2297 /*DFG: TODO |
|
2298 ds->idle = 1;*/ |
|
2299 vnc_state = vs; |
|
2300 vs->display = NULL; |
|
2301 vs->password = NULL; |
|
2302 |
|
2303 vs->lsock = -1; |
|
2304 vs->csock = -1; |
|
2305 vs->last_x = -1; |
|
2306 vs->last_y = -1; |
|
2307 |
|
2308 vs->ds = ds; |
|
2309 |
|
2310 if (keyboard_layout) |
|
2311 vs->kbd_layout = init_keyboard_layout(keyboard_layout); |
|
2312 else |
|
2313 vs->kbd_layout = init_keyboard_layout("en-us"); |
|
2314 |
|
2315 if (!vs->kbd_layout) |
|
2316 exit(1); |
|
2317 |
|
2318 vs->timer = qemu_new_timer(rt_clock, vnc_update_client, vs); |
|
2319 |
|
2320 vs->ds->data = NULL; |
|
2321 vs->ds->dpy_update = vnc_dpy_update; |
|
2322 #if 0 |
|
2323 DFG TODO |
|
2324 vs->ds->dpy_resize = vnc_dpy_resize; |
|
2325 vs->ds->dpy_refresh = NULL; |
|
2326 #endif |
|
2327 vnc_colordepth(vs->ds, 32); |
|
2328 vnc_dpy_resize(vs->ds, 640, 400); |
|
2329 |
|
2330 vs->as.freq = 44100; |
|
2331 vs->as.nchannels = 2; |
|
2332 vs->as.fmt = AUD_FMT_S16; |
|
2333 vs->as.endianness = 0; |
|
2334 } |
|
2335 |
|
2336 #ifdef CONFIG_VNC_TLS |
|
2337 static int vnc_set_x509_credential(VncState *vs, |
|
2338 const char *certdir, |
|
2339 const char *filename, |
|
2340 char **cred, |
|
2341 int ignoreMissing) |
|
2342 { |
|
2343 struct stat sb; |
|
2344 |
|
2345 if (*cred) { |
|
2346 qemu_free(*cred); |
|
2347 *cred = NULL; |
|
2348 } |
|
2349 |
|
2350 if (!(*cred = qemu_malloc(strlen(certdir) + strlen(filename) + 2))) |
|
2351 return -1; |
|
2352 |
|
2353 strcpy(*cred, certdir); |
|
2354 strcat(*cred, "/"); |
|
2355 strcat(*cred, filename); |
|
2356 |
|
2357 VNC_DEBUG("Check %s\n", *cred); |
|
2358 if (stat(*cred, &sb) < 0) { |
|
2359 qemu_free(*cred); |
|
2360 *cred = NULL; |
|
2361 if (ignoreMissing && errno == ENOENT) |
|
2362 return 0; |
|
2363 return -1; |
|
2364 } |
|
2365 |
|
2366 return 0; |
|
2367 } |
|
2368 |
|
2369 static int vnc_set_x509_credential_dir(VncState *vs, |
|
2370 const char *certdir) |
|
2371 { |
|
2372 if (vnc_set_x509_credential(vs, certdir, X509_CA_CERT_FILE, &vs->x509cacert, 0) < 0) |
|
2373 goto cleanup; |
|
2374 if (vnc_set_x509_credential(vs, certdir, X509_CA_CRL_FILE, &vs->x509cacrl, 1) < 0) |
|
2375 goto cleanup; |
|
2376 if (vnc_set_x509_credential(vs, certdir, X509_SERVER_CERT_FILE, &vs->x509cert, 0) < 0) |
|
2377 goto cleanup; |
|
2378 if (vnc_set_x509_credential(vs, certdir, X509_SERVER_KEY_FILE, &vs->x509key, 0) < 0) |
|
2379 goto cleanup; |
|
2380 |
|
2381 return 0; |
|
2382 |
|
2383 cleanup: |
|
2384 qemu_free(vs->x509cacert); |
|
2385 qemu_free(vs->x509cacrl); |
|
2386 qemu_free(vs->x509cert); |
|
2387 qemu_free(vs->x509key); |
|
2388 vs->x509cacert = vs->x509cacrl = vs->x509cert = vs->x509key = NULL; |
|
2389 return -1; |
|
2390 } |
|
2391 #endif /* CONFIG_VNC_TLS */ |
|
2392 |
|
2393 void vnc_display_close(DisplayState *ds) |
|
2394 { |
|
2395 VncState *vs = ds ? (VncState *)ds->opaque : vnc_state; |
|
2396 |
|
2397 if (vs->display) { |
|
2398 qemu_free(vs->display); |
|
2399 vs->display = NULL; |
|
2400 } |
|
2401 if (vs->lsock != -1) { |
|
2402 qemu_set_fd_handler2(vs->lsock, NULL, NULL, NULL, NULL); |
|
2403 close(vs->lsock); |
|
2404 vs->lsock = -1; |
|
2405 } |
|
2406 if (vs->csock != -1) { |
|
2407 qemu_set_fd_handler2(vs->csock, NULL, NULL, NULL, NULL); |
|
2408 closesocket(vs->csock); |
|
2409 vs->csock = -1; |
|
2410 buffer_reset(&vs->input); |
|
2411 buffer_reset(&vs->output); |
|
2412 vs->need_update = 0; |
|
2413 #ifdef CONFIG_VNC_TLS |
|
2414 if (vs->tls_session) { |
|
2415 gnutls_deinit(vs->tls_session); |
|
2416 vs->tls_session = NULL; |
|
2417 } |
|
2418 vs->wiremode = VNC_WIREMODE_CLEAR; |
|
2419 #endif /* CONFIG_VNC_TLS */ |
|
2420 } |
|
2421 vs->auth = VNC_AUTH_INVALID; |
|
2422 #ifdef CONFIG_VNC_TLS |
|
2423 vs->subauth = VNC_AUTH_INVALID; |
|
2424 vs->x509verify = 0; |
|
2425 #endif |
|
2426 audio_del(vs); |
|
2427 } |
|
2428 |
|
2429 int vnc_display_password(DisplayState *ds, const char *password) |
|
2430 { |
|
2431 VncState *vs = ds ? (VncState *)ds->opaque : vnc_state; |
|
2432 |
|
2433 if (vs->password) { |
|
2434 qemu_free(vs->password); |
|
2435 vs->password = NULL; |
|
2436 } |
|
2437 if (password && password[0]) { |
|
2438 if (!(vs->password = qemu_strdup(password))) |
|
2439 return -1; |
|
2440 } |
|
2441 |
|
2442 return 0; |
|
2443 } |
|
2444 |
|
2445 int vnc_display_open(DisplayState *ds, const char *display) |
|
2446 { |
|
2447 VncState *vs = ds ? (VncState *)ds->opaque : vnc_state; |
|
2448 const char *options; |
|
2449 int password = 0; |
|
2450 int reverse = 0; |
|
2451 int to_port = 0; |
|
2452 #ifdef CONFIG_VNC_TLS |
|
2453 int tls = 0, x509 = 0; |
|
2454 #endif |
|
2455 |
|
2456 vnc_display_close(ds); |
|
2457 if (strcmp(display, "none") == 0) |
|
2458 return 0; |
|
2459 |
|
2460 if (!(vs->display = strdup(display))) |
|
2461 return -1; |
|
2462 |
|
2463 options = display; |
|
2464 while ((options = strchr(options, ','))) { |
|
2465 options++; |
|
2466 if (strncmp(options, "password", 8) == 0) { |
|
2467 password = 1; /* Require password auth */ |
|
2468 } else if (strncmp(options, "reverse", 7) == 0) { |
|
2469 reverse = 1; |
|
2470 } else if (strncmp(options, "to=", 3) == 0) { |
|
2471 to_port = atoi(options+3) + 5900; |
|
2472 #ifdef CONFIG_VNC_TLS |
|
2473 } else if (strncmp(options, "tls", 3) == 0) { |
|
2474 tls = 1; /* Require TLS */ |
|
2475 } else if (strncmp(options, "x509", 4) == 0) { |
|
2476 char *start, *end; |
|
2477 x509 = 1; /* Require x509 certificates */ |
|
2478 if (strncmp(options, "x509verify", 10) == 0) |
|
2479 vs->x509verify = 1; /* ...and verify client certs */ |
|
2480 |
|
2481 /* Now check for 'x509=/some/path' postfix |
|
2482 * and use that to setup x509 certificate/key paths */ |
|
2483 start = strchr(options, '='); |
|
2484 end = strchr(options, ','); |
|
2485 if (start && (!end || (start < end))) { |
|
2486 int len = end ? end-(start+1) : strlen(start+1); |
|
2487 char *path = qemu_strndup(start + 1, len); |
|
2488 |
|
2489 VNC_DEBUG("Trying certificate path '%s'\n", path); |
|
2490 if (vnc_set_x509_credential_dir(vs, path) < 0) { |
|
2491 fprintf(stderr, "Failed to find x509 certificates/keys in %s\n", path); |
|
2492 qemu_free(path); |
|
2493 qemu_free(vs->display); |
|
2494 vs->display = NULL; |
|
2495 return -1; |
|
2496 } |
|
2497 qemu_free(path); |
|
2498 } else { |
|
2499 fprintf(stderr, "No certificate path provided\n"); |
|
2500 qemu_free(vs->display); |
|
2501 vs->display = NULL; |
|
2502 return -1; |
|
2503 } |
|
2504 #endif |
|
2505 } |
|
2506 } |
|
2507 |
|
2508 if (password) { |
|
2509 #ifdef CONFIG_VNC_TLS |
|
2510 if (tls) { |
|
2511 vs->auth = VNC_AUTH_VENCRYPT; |
|
2512 if (x509) { |
|
2513 VNC_DEBUG("Initializing VNC server with x509 password auth\n"); |
|
2514 vs->subauth = VNC_AUTH_VENCRYPT_X509VNC; |
|
2515 } else { |
|
2516 VNC_DEBUG("Initializing VNC server with TLS password auth\n"); |
|
2517 vs->subauth = VNC_AUTH_VENCRYPT_TLSVNC; |
|
2518 } |
|
2519 } else { |
|
2520 #endif |
|
2521 VNC_DEBUG("Initializing VNC server with password auth\n"); |
|
2522 vs->auth = VNC_AUTH_VNC; |
|
2523 #ifdef CONFIG_VNC_TLS |
|
2524 vs->subauth = VNC_AUTH_INVALID; |
|
2525 } |
|
2526 #endif |
|
2527 } else { |
|
2528 #ifdef CONFIG_VNC_TLS |
|
2529 if (tls) { |
|
2530 vs->auth = VNC_AUTH_VENCRYPT; |
|
2531 if (x509) { |
|
2532 VNC_DEBUG("Initializing VNC server with x509 no auth\n"); |
|
2533 vs->subauth = VNC_AUTH_VENCRYPT_X509NONE; |
|
2534 } else { |
|
2535 VNC_DEBUG("Initializing VNC server with TLS no auth\n"); |
|
2536 vs->subauth = VNC_AUTH_VENCRYPT_TLSNONE; |
|
2537 } |
|
2538 } else { |
|
2539 #endif |
|
2540 VNC_DEBUG("Initializing VNC server with no auth\n"); |
|
2541 vs->auth = VNC_AUTH_NONE; |
|
2542 #ifdef CONFIG_VNC_TLS |
|
2543 vs->subauth = VNC_AUTH_INVALID; |
|
2544 } |
|
2545 #endif |
|
2546 } |
|
2547 |
|
2548 if (reverse) { |
|
2549 /* connect to viewer */ |
|
2550 if (strncmp(display, "unix:", 5) == 0) |
|
2551 vs->lsock = unix_connect(display+5); |
|
2552 else |
|
2553 vs->lsock = inet_connect(display, SOCK_STREAM); |
|
2554 if (-1 == vs->lsock) { |
|
2555 free(vs->display); |
|
2556 vs->display = NULL; |
|
2557 return -1; |
|
2558 } else { |
|
2559 vs->csock = vs->lsock; |
|
2560 vs->lsock = -1; |
|
2561 vnc_connect(vs); |
|
2562 } |
|
2563 return 0; |
|
2564 |
|
2565 } else { |
|
2566 /* listen for connects */ |
|
2567 char *dpy; |
|
2568 dpy = qemu_malloc(256); |
|
2569 if (strncmp(display, "unix:", 5) == 0) { |
|
2570 strcpy(dpy, "unix:"); |
|
2571 vs->lsock = unix_listen(display+5, dpy+5, 256-5); |
|
2572 } else { |
|
2573 vs->lsock = inet_listen(display, dpy, 256, SOCK_STREAM, 5900); |
|
2574 } |
|
2575 if (-1 == vs->lsock) { |
|
2576 free(dpy); |
|
2577 return -1; |
|
2578 } else { |
|
2579 free(vs->display); |
|
2580 vs->display = dpy; |
|
2581 } |
|
2582 } |
|
2583 |
|
2584 return qemu_set_fd_handler2(vs->lsock, vnc_listen_poll, vnc_listen_read, NULL, vs); |
|
2585 } |