]> git.proxmox.com Git - pve-qemu-kvm.git/blame - debian/patches/pve-auth.patch
Fix CVE-2016-2841, CVE-2016-2857, CVE-2016-2858
[pve-qemu-kvm.git] / debian / patches / pve-auth.patch
CommitLineData
4676c0af
DM
1Index: new/ui/vnc.c
2===================================================================
24bb7da3
DM
3--- new.orig/ui/vnc.c 2014-11-20 06:50:51.000000000 +0100
4+++ new/ui/vnc.c 2014-11-20 06:50:55.000000000 +0100
3fe80761 5@@ -46,6 +46,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 */
4676c0af 129
074210ad 130 static int vnc_cursor_define(VncState *vs);
24bb7da3 131@@ -3156,6 +3275,7 @@
4676c0af
DM
132 tls = 1; /* Require TLS */
133 } else if (strncmp(options, "x509", 4) == 0) {
134 char *start, *end;
135+ tls = 1; /* Require TLS */
136 x509 = 1; /* Require x509 certificates */
137 if (strncmp(options, "x509verify", 10) == 0)
138 vs->tls.x509verify = 1; /* ...and verify client certs */
24bb7da3 139@@ -3176,8 +3296,10 @@
4676c0af 140 }
07a7849d 141 g_free(path);
4676c0af 142 } else {
e96de165
DM
143- error_setg(errp, "No certificate path provided");
144- goto fail;
07a7849d 145+ if (pve_tls_set_x509_creds_dir(vs) < 0) {
e96de165
DM
146+ error_setg(errp, "No certificate path provided");
147+ goto fail;
148+ }
4676c0af
DM
149 }
150 #endif
151 #if defined(CONFIG_VNC_TLS) || defined(CONFIG_VNC_SASL)
24bb7da3 152@@ -3250,10 +3372,10 @@
4676c0af
DM
153 vs->auth = VNC_AUTH_VENCRYPT;
154 if (x509) {
155 VNC_DEBUG("Initializing VNC server with x509 password auth\n");
156- vs->subauth = VNC_AUTH_VENCRYPT_X509VNC;
157+ vs->subauth = VNC_AUTH_VENCRYPT_X509PLAIN;
158 } else {
159 VNC_DEBUG("Initializing VNC server with TLS password auth\n");
160- vs->subauth = VNC_AUTH_VENCRYPT_TLSVNC;
161+ vs->subauth = VNC_AUTH_VENCRYPT_TLSPLAIN;
162 }
163 } else {
164 #endif /* CONFIG_VNC_TLS */
165Index: new/ui/vnc-auth-vencrypt.c
166===================================================================
24bb7da3
DM
167--- new.orig/ui/vnc-auth-vencrypt.c 2014-11-20 06:45:06.000000000 +0100
168+++ new/ui/vnc-auth-vencrypt.c 2014-11-20 06:50:55.000000000 +0100
074210ad 169@@ -26,6 +26,107 @@
4676c0af
DM
170
171 #include "vnc.h"
074210ad
DM
172 #include "qemu/main-loop.h"
173+#include "qemu/sockets.h"
174+
4676c0af
DM
175+static int protocol_client_auth_plain(VncState *vs, uint8_t *data, size_t len)
176+{
177+ const char *err = NULL;
178+ char username[256];
179+ char passwd[512];
180+
181+ char clientip[256];
182+ clientip[0] = 0;
183+ struct sockaddr_in client;
184+ socklen_t addrlen = sizeof(client);
185+ if (getpeername(vs->csock, &client, &addrlen) == 0) {
07a7849d 186+ inet_ntop(client.sin_family, &client.sin_addr,
4676c0af
DM
187+ clientip, sizeof(clientip));
188+ }
189+
190+ if ((len != (vs->username_len + vs->password_len)) ||
191+ (vs->username_len >= (sizeof(username)-1)) ||
192+ (vs->password_len >= (sizeof(passwd)-1)) ) {
193+ err = "Got unexpected data length";
194+ goto err;
195+ }
196+
197+ strncpy(username, (char *)data, vs->username_len);
198+ username[vs->username_len] = 0;
199+ strncpy(passwd, (char *)data + vs->username_len, vs->password_len);
200+ passwd[vs->password_len] = 0;
201+
202+ VNC_DEBUG("AUTH PLAIN username: %s pw: %s\n", username, passwd);
203+
204+ if (pve_auth_verify(clientip, username, passwd) == 0) {
205+ vnc_write_u32(vs, 0); /* Accept auth completion */
206+ start_client_init(vs);
207+ return 0;
208+ }
209+
210+ err = "Authentication failed";
211+err:
212+ if (err) {
213+ VNC_DEBUG("AUTH PLAIN ERROR: %s\n", err);
214+ vnc_write_u32(vs, 1); /* Reject auth */
215+ if (vs->minor >= 8) {
216+ int elen = strlen(err);
217+ vnc_write_u32(vs, elen);
218+ vnc_write(vs, err, elen);
219+ }
220+ }
221+ vnc_flush(vs);
222+ vnc_client_error(vs);
223+
224+ return 0;
225+
226+}
227+
228+static int protocol_client_auth_plain_start(VncState *vs, uint8_t *data, size_t len)
229+{
230+ uint32_t ulen = read_u32(data, 0);
231+ uint32_t pwlen = read_u32(data, 4);
232+ const char *err = NULL;
233+
234+ VNC_DEBUG("AUTH PLAIN START %u %u\n", ulen, pwlen);
235+
236+ if (!ulen) {
237+ err = "No User name.";
238+ goto err;
239+ }
240+ if (ulen >= 255) {
241+ err = "User name too long.";
242+ goto err;
243+ }
244+ if (!pwlen) {
245+ err = "Password too short";
246+ goto err;
247+ }
248+ if (pwlen >= 511) {
249+ err = "Password too long.";
250+ goto err;
251+ }
252+
253+ vs->username_len = ulen;
254+ vs->password_len = pwlen;
255+
256+ vnc_read_when(vs, protocol_client_auth_plain, ulen + pwlen);
257+
258+ return 0;
259+err:
260+ if (err) {
261+ VNC_DEBUG("AUTH PLAIN ERROR: %s\n", err);
262+ vnc_write_u32(vs, 1); /* Reject auth */
263+ if (vs->minor >= 8) {
264+ int elen = strlen(err);
265+ vnc_write_u32(vs, elen);
266+ vnc_write(vs, err, elen);
267+ }
268+ }
269+ vnc_flush(vs);
270+ vnc_client_error(vs);
271+
272+ return 0;
273+}
274
275 static void start_auth_vencrypt_subauth(VncState *vs)
276 {
074210ad 277@@ -37,6 +138,12 @@
4676c0af
DM
278 start_client_init(vs);
279 break;
280
281+ case VNC_AUTH_VENCRYPT_TLSPLAIN:
282+ case VNC_AUTH_VENCRYPT_X509PLAIN:
283+ VNC_DEBUG("Start TLS auth PLAIN\n");
284+ vnc_read_when(vs, protocol_client_auth_plain_start, 8);
285+ break;
286+
287 case VNC_AUTH_VENCRYPT_TLSVNC:
288 case VNC_AUTH_VENCRYPT_X509VNC:
289 VNC_DEBUG("Start TLS auth VNC\n");
290Index: new/ui/vnc.h
291===================================================================
24bb7da3
DM
292--- new.orig/ui/vnc.h 2014-11-20 06:45:06.000000000 +0100
293+++ new/ui/vnc.h 2014-11-20 06:50:55.000000000 +0100
294@@ -282,6 +282,8 @@
4676c0af
DM
295 char challenge[VNC_AUTH_CHALLENGE_SIZE];
296 #ifdef CONFIG_VNC_TLS
297 int subauth; /* Used by VeNCrypt */
298+ int username_len;
299+ int password_len;
300 VncStateTLS tls;
301 #endif
302 #ifdef CONFIG_VNC_SASL
24bb7da3 303@@ -597,4 +599,6 @@
07a7849d
DM
304 int vnc_zywrle_send_framebuffer_update(VncState *vs, int x, int y, int w, int h);
305 void vnc_zrle_clear(VncState *vs);
306
307+int pve_auth_verify(const char *clientip, const char *username, const char *passwd);
308+
309 #endif /* __QEMU_VNC_H */
4676c0af
DM
310Index: new/ui/vnc-tls.c
311===================================================================
24bb7da3
DM
312--- new.orig/ui/vnc-tls.c 2014-11-20 06:45:06.000000000 +0100
313+++ new/ui/vnc-tls.c 2014-11-20 06:50:55.000000000 +0100
07a7849d 314@@ -302,6 +302,14 @@
4676c0af 315
07a7849d
DM
316 static int vnc_set_gnutls_priority(gnutls_session_t s, int x509)
317 {
4676c0af
DM
318+ /* optimize for speed */
319+ static const int ciphers[] = {
320+ GNUTLS_CIPHER_ARCFOUR_128,
321+ GNUTLS_CIPHER_AES_128_CBC,
322+ GNUTLS_CIPHER_3DES_CBC,
323+ 0
324+ };
325+
07a7849d
DM
326 static const int cert_types[] = { GNUTLS_CRT_X509, 0 };
327 static const int protocols[] = {
328 GNUTLS_TLS1_1, GNUTLS_TLS1_0, GNUTLS_SSL3, 0
329@@ -313,6 +321,11 @@
330 };
331 int rc;
4676c0af 332
07a7849d
DM
333+ rc = gnutls_cipher_set_priority(s, ciphers);
334+ if (rc != GNUTLS_E_SUCCESS) {
335+ return -1;
336+ }
337+
338 rc = gnutls_kx_set_priority(s, x509 ? kx_x509 : kx_anon);
339 if (rc != GNUTLS_E_SUCCESS) {
340 return -1;
24bb7da3 341@@ -462,6 +475,24 @@
4676c0af
DM
342 return 0;
343 }
344
345+int pve_tls_set_x509_creds_dir(VncDisplay *vd)
346+{
347+ if (vnc_set_x509_credential(vd, "/etc/pve", "pve-root-ca.pem", &vd->tls.x509cacert, 0) < 0)
348+ goto cleanup;
349+ if (vnc_set_x509_credential(vd, "/etc/pve/local", "pve-ssl.pem", &vd->tls.x509cert, 0) < 0)
350+ goto cleanup;
351+ if (vnc_set_x509_credential(vd, "/etc/pve/local", "pve-ssl.key", &vd->tls.x509key, 0) < 0)
352+ goto cleanup;
353+
354+ return 0;
355+
356+ cleanup:
07a7849d
DM
357+ g_free(vd->tls.x509cacert);
358+ g_free(vd->tls.x509cert);
359+ g_free(vd->tls.x509key);
4676c0af
DM
360+ vd->tls.x509cacert = vd->tls.x509cacrl = vd->tls.x509cert = vd->tls.x509key = NULL;
361+ return -1;
362+}
363
364 int vnc_tls_set_x509_creds_dir(VncDisplay *vd,
365 const char *certdir)
366Index: new/ui/vnc-tls.h
367===================================================================
24bb7da3
DM
368--- new.orig/ui/vnc-tls.h 2014-11-20 06:45:06.000000000 +0100
369+++ new/ui/vnc-tls.h 2014-11-20 06:50:55.000000000 +0100
4676c0af
DM
370@@ -68,6 +68,8 @@
371
372 int vnc_tls_validate_certificate(VncState *vs);
373
374+int pve_tls_set_x509_creds_dir(VncDisplay *vd);
375+
376 int vnc_tls_set_x509_creds_dir(VncDisplay *vd,
377 const char *path);
378
379Index: new/vl.c
380===================================================================
24bb7da3
DM
381--- new.orig/vl.c 2014-11-20 06:50:44.000000000 +0100
382+++ new/vl.c 2014-11-20 06:50:55.000000000 +0100
383@@ -3573,6 +3573,7 @@
4676c0af
DM
384 fprintf(stderr, "Invalid ID\n");
385 exit(1);
24565bc0
DM
386 }
387+ pve_auth_setup(fairsched_id);
388 break;
389 case QEMU_OPTION_cpuunits:
390 cpuunits = atoi(optarg);
92bf040c 391Index: new/include/ui/console.h
a023e148 392===================================================================
24bb7da3
DM
393--- new.orig/include/ui/console.h 2014-11-20 06:45:06.000000000 +0100
394+++ new/include/ui/console.h 2014-11-20 06:50:55.000000000 +0100
395@@ -327,6 +327,7 @@
a023e148
DM
396 void cocoa_display_init(DisplayState *ds, int full_screen);
397
398 /* vnc.c */
399+void pve_auth_setup(int vmid);
400 void vnc_display_init(DisplayState *ds);
e96de165 401 void vnc_display_open(DisplayState *ds, const char *display, Error **errp);
074210ad 402 void vnc_display_add_client(DisplayState *ds, int csock, bool skipauth);