]>
Commit | Line | Data |
---|---|---|
4676c0af DM |
1 | Index: new/ui/vnc.c |
2 | =================================================================== | |
2802c577 DM |
3 | --- new.orig/ui/vnc.c 2012-09-24 07:15:22.000000000 +0200 |
4 | +++ new/ui/vnc.c 2012-09-24 07:15:24.000000000 +0200 | |
5 | @@ -43,6 +43,125 @@ | |
4676c0af DM |
6 | #include "vnc_keysym.h" |
7 | #include "d3des.h" | |
8 | ||
9 | +static int pve_vmid = 0; | |
10 | + | |
11 | +void pve_auth_setup(int vmid) { | |
12 | + pve_vmid = vmid; | |
13 | +} | |
14 | + | |
15 | +static char * | |
16 | +urlencode(char *buf, const char *value) | |
17 | +{ | |
18 | + static const char *hexchar = "0123456789abcdef"; | |
19 | + char *p = buf; | |
20 | + int i; | |
21 | + int l = strlen(value); | |
22 | + for (i = 0; i < l; i++) { | |
23 | + char c = value[i]; | |
24 | + if (('a' <= c && c <= 'z') || | |
25 | + ('A' <= c && c <= 'Z') || | |
26 | + ('0' <= c && c <= '9')) { | |
27 | + *p++ = c; | |
28 | + } else if (c == 32) { | |
29 | + *p++ = '+'; | |
30 | + } else { | |
31 | + *p++ = '%'; | |
32 | + *p++ = hexchar[c >> 4]; | |
33 | + *p++ = hexchar[c & 15]; | |
34 | + } | |
35 | + } | |
36 | + *p = 0; | |
37 | + | |
38 | + return p; | |
39 | +} | |
40 | + | |
41 | +int | |
42 | +pve_auth_verify(const char *clientip, const char *username, const char *passwd) | |
43 | +{ | |
44 | + struct sockaddr_in server; | |
45 | + | |
46 | + int sfd = socket(AF_INET, SOCK_STREAM, 0); | |
47 | + if (sfd == -1) { | |
48 | + perror("pve_auth_verify: socket failed"); | |
49 | + return -1; | |
50 | + } | |
51 | + | |
52 | + struct hostent *he; | |
53 | + if ((he = gethostbyname("localhost")) == NULL) { | |
54 | + fprintf(stderr, "pve_auth_verify: error resolving hostname\n"); | |
55 | + goto err; | |
56 | + } | |
57 | + | |
58 | + memcpy(&server.sin_addr, he->h_addr_list[0], he->h_length); | |
59 | + server.sin_family = AF_INET; | |
60 | + server.sin_port = htons(85); | |
61 | + | |
62 | + if (connect(sfd, (struct sockaddr *)&server, sizeof(server))) { | |
63 | + perror("pve_auth_verify: error connecting to server"); | |
64 | + goto err; | |
65 | + } | |
66 | + | |
67 | + char buf[8192]; | |
68 | + char form[8192]; | |
69 | + | |
70 | + char *p = form; | |
71 | + p = urlencode(p, "username"); | |
72 | + *p++ = '='; | |
73 | + p = urlencode(p, username); | |
74 | + | |
75 | + *p++ = '&'; | |
76 | + p = urlencode(p, "password"); | |
77 | + *p++ = '='; | |
78 | + p = urlencode(p, passwd); | |
79 | + | |
80 | + *p++ = '&'; | |
81 | + p = urlencode(p, "path"); | |
82 | + *p++ = '='; | |
83 | + char authpath[256]; | |
84 | + sprintf(authpath, "/vms/%d", pve_vmid); | |
85 | + p = urlencode(p, authpath); | |
86 | + | |
87 | + *p++ = '&'; | |
88 | + p = urlencode(p, "privs"); | |
89 | + *p++ = '='; | |
90 | + p = urlencode(p, "VM.Console"); | |
91 | + | |
92 | + sprintf(buf, "POST /api2/json/access/ticket HTTP/1.1\n" | |
93 | + "Host: localhost:85\n" | |
94 | + "Connection: close\n" | |
95 | + "PVEClientIP: %s\n" | |
96 | + "Content-Type: application/x-www-form-urlencoded\n" | |
97 | + "Content-Length: %zd\n\n%s\n", clientip, strlen(form), form); | |
98 | + ssize_t len = strlen(buf); | |
99 | + ssize_t sb = send(sfd, buf, len, 0); | |
100 | + if (sb < 0) { | |
101 | + perror("pve_auth_verify: send failed"); | |
102 | + goto err; | |
103 | + } | |
104 | + if (sb != len) { | |
105 | + fprintf(stderr, "pve_auth_verify: partial send error\n"); | |
106 | + goto err; | |
107 | + } | |
108 | + | |
109 | + len = recv(sfd, buf, sizeof(buf) - 1, 0); | |
110 | + if (len < 0) { | |
111 | + perror("pve_auth_verify: recv failed"); | |
112 | + goto err; | |
113 | + } | |
114 | + | |
115 | + buf[len] = 0; | |
116 | + | |
117 | + //printf("DATA:%s\n", buf); | |
118 | + | |
119 | + shutdown(sfd, SHUT_RDWR); | |
120 | + | |
121 | + return strncmp(buf, "HTTP/1.1 200 OK", 15); | |
122 | + | |
123 | +err: | |
124 | + shutdown(sfd, SHUT_RDWR); | |
125 | + return -1; | |
126 | +} | |
127 | + | |
128 | static VncDisplay *vnc_display; /* needed for info vnc */ | |
129 | static DisplayChangeListener *dcl; | |
130 | ||
2802c577 | 131 | @@ -1891,7 +2010,7 @@ |
4676c0af DM |
132 | static void set_pixel_conversion(VncState *vs) |
133 | { | |
134 | if ((vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG) == | |
135 | - (vs->ds->surface->flags & QEMU_BIG_ENDIAN_FLAG) && | |
136 | + (vs->ds->surface->flags & QEMU_BIG_ENDIAN_FLAG) && | |
137 | !memcmp(&(vs->clientds.pf), &(vs->ds->surface->pf), sizeof(PixelFormat))) { | |
138 | vs->write_pixels = vnc_write_pixels_copy; | |
139 | vnc_hextile_set_pixel_conversion(vs, 0); | |
2802c577 | 140 | @@ -1980,7 +2099,7 @@ |
4676c0af DM |
141 | vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE); |
142 | vnc_write_u8(vs, 0); | |
143 | vnc_write_u16(vs, 1); /* number of rects */ | |
144 | - vnc_framebuffer_update(vs, 0, 0, ds_get_width(vs->ds), | |
145 | + vnc_framebuffer_update(vs, 0, 0, ds_get_width(vs->ds), | |
146 | ds_get_height(vs->ds), VNC_ENCODING_WMVi); | |
147 | pixel_format_message(vs); | |
148 | vnc_unlock_output(vs); | |
2802c577 | 149 | @@ -2875,7 +2994,7 @@ |
4676c0af DM |
150 | char *vnc_display_local_addr(DisplayState *ds) |
151 | { | |
152 | VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display; | |
153 | - | |
154 | + | |
155 | return vnc_socket_local_addr("%s:%s", vs->lsock); | |
156 | } | |
157 | ||
2802c577 | 158 | @@ -2934,6 +3053,7 @@ |
4676c0af DM |
159 | tls = 1; /* Require TLS */ |
160 | } else if (strncmp(options, "x509", 4) == 0) { | |
161 | char *start, *end; | |
162 | + tls = 1; /* Require TLS */ | |
163 | x509 = 1; /* Require x509 certificates */ | |
164 | if (strncmp(options, "x509verify", 10) == 0) | |
165 | vs->tls.x509verify = 1; /* ...and verify client certs */ | |
2802c577 | 166 | @@ -2956,10 +3076,12 @@ |
4676c0af | 167 | } |
07a7849d | 168 | g_free(path); |
4676c0af DM |
169 | } else { |
170 | - fprintf(stderr, "No certificate path provided\n"); | |
07a7849d | 171 | - g_free(vs->display); |
4676c0af DM |
172 | - vs->display = NULL; |
173 | - return -1; | |
07a7849d | 174 | + if (pve_tls_set_x509_creds_dir(vs) < 0) { |
4676c0af | 175 | + fprintf(stderr, "No certificate path provided\n"); |
07a7849d | 176 | + g_free(vs->display); |
4676c0af DM |
177 | + vs->display = NULL; |
178 | + return -1; | |
179 | + } | |
180 | } | |
181 | #endif | |
182 | #if defined(CONFIG_VNC_TLS) || defined(CONFIG_VNC_SASL) | |
2802c577 | 183 | @@ -3025,10 +3147,10 @@ |
4676c0af DM |
184 | vs->auth = VNC_AUTH_VENCRYPT; |
185 | if (x509) { | |
186 | VNC_DEBUG("Initializing VNC server with x509 password auth\n"); | |
187 | - vs->subauth = VNC_AUTH_VENCRYPT_X509VNC; | |
188 | + vs->subauth = VNC_AUTH_VENCRYPT_X509PLAIN; | |
189 | } else { | |
190 | VNC_DEBUG("Initializing VNC server with TLS password auth\n"); | |
191 | - vs->subauth = VNC_AUTH_VENCRYPT_TLSVNC; | |
192 | + vs->subauth = VNC_AUTH_VENCRYPT_TLSPLAIN; | |
193 | } | |
194 | } else { | |
195 | #endif /* CONFIG_VNC_TLS */ | |
196 | Index: new/ui/vnc-auth-vencrypt.c | |
197 | =================================================================== | |
2802c577 DM |
198 | --- new.orig/ui/vnc-auth-vencrypt.c 2012-09-24 07:15:00.000000000 +0200 |
199 | +++ new/ui/vnc-auth-vencrypt.c 2012-09-24 07:15:24.000000000 +0200 | |
4676c0af DM |
200 | @@ -25,7 +25,107 @@ |
201 | */ | |
202 | ||
203 | #include "vnc.h" | |
204 | +#include "qemu_socket.h" | |
205 | ||
206 | +static int protocol_client_auth_plain(VncState *vs, uint8_t *data, size_t len) | |
207 | +{ | |
208 | + const char *err = NULL; | |
209 | + char username[256]; | |
210 | + char passwd[512]; | |
211 | + | |
212 | + char clientip[256]; | |
213 | + clientip[0] = 0; | |
214 | + struct sockaddr_in client; | |
215 | + socklen_t addrlen = sizeof(client); | |
216 | + if (getpeername(vs->csock, &client, &addrlen) == 0) { | |
07a7849d | 217 | + inet_ntop(client.sin_family, &client.sin_addr, |
4676c0af DM |
218 | + clientip, sizeof(clientip)); |
219 | + } | |
220 | + | |
221 | + if ((len != (vs->username_len + vs->password_len)) || | |
222 | + (vs->username_len >= (sizeof(username)-1)) || | |
223 | + (vs->password_len >= (sizeof(passwd)-1)) ) { | |
224 | + err = "Got unexpected data length"; | |
225 | + goto err; | |
226 | + } | |
227 | + | |
228 | + strncpy(username, (char *)data, vs->username_len); | |
229 | + username[vs->username_len] = 0; | |
230 | + strncpy(passwd, (char *)data + vs->username_len, vs->password_len); | |
231 | + passwd[vs->password_len] = 0; | |
232 | + | |
233 | + VNC_DEBUG("AUTH PLAIN username: %s pw: %s\n", username, passwd); | |
234 | + | |
235 | + if (pve_auth_verify(clientip, username, passwd) == 0) { | |
236 | + vnc_write_u32(vs, 0); /* Accept auth completion */ | |
237 | + start_client_init(vs); | |
238 | + return 0; | |
239 | + } | |
240 | + | |
241 | + err = "Authentication failed"; | |
242 | +err: | |
243 | + if (err) { | |
244 | + VNC_DEBUG("AUTH PLAIN ERROR: %s\n", err); | |
245 | + vnc_write_u32(vs, 1); /* Reject auth */ | |
246 | + if (vs->minor >= 8) { | |
247 | + int elen = strlen(err); | |
248 | + vnc_write_u32(vs, elen); | |
249 | + vnc_write(vs, err, elen); | |
250 | + } | |
251 | + } | |
252 | + vnc_flush(vs); | |
253 | + vnc_client_error(vs); | |
254 | + | |
255 | + return 0; | |
256 | + | |
257 | +} | |
258 | + | |
259 | +static int protocol_client_auth_plain_start(VncState *vs, uint8_t *data, size_t len) | |
260 | +{ | |
261 | + uint32_t ulen = read_u32(data, 0); | |
262 | + uint32_t pwlen = read_u32(data, 4); | |
263 | + const char *err = NULL; | |
264 | + | |
265 | + VNC_DEBUG("AUTH PLAIN START %u %u\n", ulen, pwlen); | |
266 | + | |
267 | + if (!ulen) { | |
268 | + err = "No User name."; | |
269 | + goto err; | |
270 | + } | |
271 | + if (ulen >= 255) { | |
272 | + err = "User name too long."; | |
273 | + goto err; | |
274 | + } | |
275 | + if (!pwlen) { | |
276 | + err = "Password too short"; | |
277 | + goto err; | |
278 | + } | |
279 | + if (pwlen >= 511) { | |
280 | + err = "Password too long."; | |
281 | + goto err; | |
282 | + } | |
283 | + | |
284 | + vs->username_len = ulen; | |
285 | + vs->password_len = pwlen; | |
286 | + | |
287 | + vnc_read_when(vs, protocol_client_auth_plain, ulen + pwlen); | |
288 | + | |
289 | + return 0; | |
290 | +err: | |
291 | + if (err) { | |
292 | + VNC_DEBUG("AUTH PLAIN ERROR: %s\n", err); | |
293 | + vnc_write_u32(vs, 1); /* Reject auth */ | |
294 | + if (vs->minor >= 8) { | |
295 | + int elen = strlen(err); | |
296 | + vnc_write_u32(vs, elen); | |
297 | + vnc_write(vs, err, elen); | |
298 | + } | |
299 | + } | |
300 | + vnc_flush(vs); | |
301 | + vnc_client_error(vs); | |
302 | + | |
303 | + return 0; | |
304 | +} | |
305 | ||
306 | static void start_auth_vencrypt_subauth(VncState *vs) | |
307 | { | |
308 | @@ -37,6 +137,12 @@ | |
309 | start_client_init(vs); | |
310 | break; | |
311 | ||
312 | + case VNC_AUTH_VENCRYPT_TLSPLAIN: | |
313 | + case VNC_AUTH_VENCRYPT_X509PLAIN: | |
314 | + VNC_DEBUG("Start TLS auth PLAIN\n"); | |
315 | + vnc_read_when(vs, protocol_client_auth_plain_start, 8); | |
316 | + break; | |
317 | + | |
318 | case VNC_AUTH_VENCRYPT_TLSVNC: | |
319 | case VNC_AUTH_VENCRYPT_X509VNC: | |
320 | VNC_DEBUG("Start TLS auth VNC\n"); | |
321 | Index: new/ui/vnc.h | |
322 | =================================================================== | |
2802c577 DM |
323 | --- new.orig/ui/vnc.h 2012-09-24 07:15:00.000000000 +0200 |
324 | +++ new/ui/vnc.h 2012-09-24 07:15:24.000000000 +0200 | |
325 | @@ -263,6 +263,8 @@ | |
4676c0af DM |
326 | char challenge[VNC_AUTH_CHALLENGE_SIZE]; |
327 | #ifdef CONFIG_VNC_TLS | |
328 | int subauth; /* Used by VeNCrypt */ | |
329 | + int username_len; | |
330 | + int password_len; | |
331 | VncStateTLS tls; | |
332 | #endif | |
333 | #ifdef CONFIG_VNC_SASL | |
2802c577 | 334 | @@ -554,4 +556,6 @@ |
07a7849d DM |
335 | int vnc_zywrle_send_framebuffer_update(VncState *vs, int x, int y, int w, int h); |
336 | void vnc_zrle_clear(VncState *vs); | |
337 | ||
338 | +int pve_auth_verify(const char *clientip, const char *username, const char *passwd); | |
339 | + | |
340 | #endif /* __QEMU_VNC_H */ | |
4676c0af DM |
341 | Index: new/ui/vnc-tls.c |
342 | =================================================================== | |
2802c577 DM |
343 | --- new.orig/ui/vnc-tls.c 2012-09-24 07:15:00.000000000 +0200 |
344 | +++ new/ui/vnc-tls.c 2012-09-24 07:15:24.000000000 +0200 | |
07a7849d | 345 | @@ -302,6 +302,14 @@ |
4676c0af | 346 | |
07a7849d DM |
347 | static int vnc_set_gnutls_priority(gnutls_session_t s, int x509) |
348 | { | |
4676c0af DM |
349 | + /* optimize for speed */ |
350 | + static const int ciphers[] = { | |
351 | + GNUTLS_CIPHER_ARCFOUR_128, | |
352 | + GNUTLS_CIPHER_AES_128_CBC, | |
353 | + GNUTLS_CIPHER_3DES_CBC, | |
354 | + 0 | |
355 | + }; | |
356 | + | |
07a7849d DM |
357 | static const int cert_types[] = { GNUTLS_CRT_X509, 0 }; |
358 | static const int protocols[] = { | |
359 | GNUTLS_TLS1_1, GNUTLS_TLS1_0, GNUTLS_SSL3, 0 | |
360 | @@ -313,6 +321,11 @@ | |
361 | }; | |
362 | int rc; | |
4676c0af | 363 | |
07a7849d DM |
364 | + rc = gnutls_cipher_set_priority(s, ciphers); |
365 | + if (rc != GNUTLS_E_SUCCESS) { | |
366 | + return -1; | |
367 | + } | |
368 | + | |
369 | rc = gnutls_kx_set_priority(s, x509 ? kx_x509 : kx_anon); | |
370 | if (rc != GNUTLS_E_SUCCESS) { | |
371 | return -1; | |
372 | @@ -449,6 +462,24 @@ | |
4676c0af DM |
373 | return 0; |
374 | } | |
375 | ||
376 | +int pve_tls_set_x509_creds_dir(VncDisplay *vd) | |
377 | +{ | |
378 | + if (vnc_set_x509_credential(vd, "/etc/pve", "pve-root-ca.pem", &vd->tls.x509cacert, 0) < 0) | |
379 | + goto cleanup; | |
380 | + if (vnc_set_x509_credential(vd, "/etc/pve/local", "pve-ssl.pem", &vd->tls.x509cert, 0) < 0) | |
381 | + goto cleanup; | |
382 | + if (vnc_set_x509_credential(vd, "/etc/pve/local", "pve-ssl.key", &vd->tls.x509key, 0) < 0) | |
383 | + goto cleanup; | |
384 | + | |
385 | + return 0; | |
386 | + | |
387 | + cleanup: | |
07a7849d DM |
388 | + g_free(vd->tls.x509cacert); |
389 | + g_free(vd->tls.x509cert); | |
390 | + g_free(vd->tls.x509key); | |
4676c0af DM |
391 | + vd->tls.x509cacert = vd->tls.x509cacrl = vd->tls.x509cert = vd->tls.x509key = NULL; |
392 | + return -1; | |
393 | +} | |
394 | ||
395 | int vnc_tls_set_x509_creds_dir(VncDisplay *vd, | |
396 | const char *certdir) | |
397 | Index: new/ui/vnc-tls.h | |
398 | =================================================================== | |
2802c577 DM |
399 | --- new.orig/ui/vnc-tls.h 2012-09-24 07:15:00.000000000 +0200 |
400 | +++ new/ui/vnc-tls.h 2012-09-24 07:15:24.000000000 +0200 | |
4676c0af DM |
401 | @@ -68,6 +68,8 @@ |
402 | ||
403 | int vnc_tls_validate_certificate(VncState *vs); | |
404 | ||
405 | +int pve_tls_set_x509_creds_dir(VncDisplay *vd); | |
406 | + | |
407 | int vnc_tls_set_x509_creds_dir(VncDisplay *vd, | |
408 | const char *path); | |
409 | ||
410 | Index: new/vl.c | |
411 | =================================================================== | |
2802c577 DM |
412 | --- new.orig/vl.c 2012-09-24 07:15:20.000000000 +0200 |
413 | +++ new/vl.c 2012-09-24 07:15:24.000000000 +0200 | |
414 | @@ -3133,6 +3133,7 @@ | |
4676c0af DM |
415 | fprintf(stderr, "Invalid ID\n"); |
416 | exit(1); | |
24565bc0 DM |
417 | } |
418 | + pve_auth_setup(fairsched_id); | |
419 | break; | |
420 | case QEMU_OPTION_cpuunits: | |
421 | cpuunits = atoi(optarg); | |
a023e148 DM |
422 | Index: new/console.h |
423 | =================================================================== | |
2802c577 DM |
424 | --- new.orig/console.h 2012-09-24 07:15:00.000000000 +0200 |
425 | +++ new/console.h 2012-09-24 07:15:24.000000000 +0200 | |
426 | @@ -374,6 +374,7 @@ | |
a023e148 DM |
427 | void cocoa_display_init(DisplayState *ds, int full_screen); |
428 | ||
429 | /* vnc.c */ | |
430 | +void pve_auth_setup(int vmid); | |
431 | void vnc_display_init(DisplayState *ds); | |
432 | void vnc_display_close(DisplayState *ds); | |
433 | int vnc_display_open(DisplayState *ds, const char *display); |