2882a357d8963dc3fce8ef58bab4bf5106e2c92f
[qemu] / vnc-auth-sasl.c
1 /*
2  * QEMU VNC display driver: SASL auth protocol
3  *
4  * Copyright (C) 2009 Red Hat, Inc
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  * THE SOFTWARE.
23  */
24
25 #include "vnc.h"
26
27 /* Max amount of data we send/recv for SASL steps to prevent DOS */
28 #define SASL_DATA_MAX_LEN (1024 * 1024)
29
30
31 void vnc_sasl_client_cleanup(VncState *vs)
32 {
33     if (vs->sasl.conn) {
34         vs->sasl.runSSF = vs->sasl.waitWriteSSF = vs->sasl.wantSSF = 0;
35         vs->sasl.encodedLength = vs->sasl.encodedOffset = 0;
36         vs->sasl.encoded = NULL;
37         free(vs->sasl.username);
38         free(vs->sasl.mechlist);
39         vs->sasl.username = vs->sasl.mechlist = NULL;
40         sasl_dispose(&vs->sasl.conn);
41         vs->sasl.conn = NULL;
42     }
43 }
44
45
46 long vnc_client_write_sasl(VncState *vs)
47 {
48     long ret;
49
50     VNC_DEBUG("Write SASL: Pending output %p size %d offset %d Encoded: %p size %d offset %d\n",
51               vs->output.buffer, vs->output.capacity, vs->output.offset,
52               vs->sasl.encoded, vs->sasl.encodedLength, vs->sasl.encodedOffset);
53
54     if (!vs->sasl.encoded) {
55         int err;
56         err = sasl_encode(vs->sasl.conn,
57                           (char *)vs->output.buffer,
58                           vs->output.offset,
59                           (const char **)&vs->sasl.encoded,
60                           &vs->sasl.encodedLength);
61         if (err != SASL_OK)
62             return vnc_client_io_error(vs, -1, EIO);
63
64         vs->sasl.encodedOffset = 0;
65     }
66
67     ret = vnc_client_write_buf(vs,
68                                vs->sasl.encoded + vs->sasl.encodedOffset,
69                                vs->sasl.encodedLength - vs->sasl.encodedOffset);
70     if (!ret)
71         return 0;
72
73     vs->sasl.encodedOffset += ret;
74     if (vs->sasl.encodedOffset == vs->sasl.encodedLength) {
75         vs->output.offset = 0;
76         vs->sasl.encoded = NULL;
77         vs->sasl.encodedOffset = vs->sasl.encodedLength = 0;
78     }
79
80     /* Can't merge this block with one above, because
81      * someone might have written more unencrypted
82      * data in vs->output while we were processing
83      * SASL encoded output
84      */
85     if (vs->output.offset == 0) {
86         qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs);
87     }
88
89     return ret;
90 }
91
92
93 long vnc_client_read_sasl(VncState *vs)
94 {
95     long ret;
96     uint8_t encoded[4096];
97     const char *decoded;
98     unsigned int decodedLen;
99     int err;
100
101     ret = vnc_client_read_buf(vs, encoded, sizeof(encoded));
102     if (!ret)
103         return 0;
104
105     err = sasl_decode(vs->sasl.conn,
106                       (char *)encoded, ret,
107                       &decoded, &decodedLen);
108
109     if (err != SASL_OK)
110         return vnc_client_io_error(vs, -1, -EIO);
111     VNC_DEBUG("Read SASL Encoded %p size %ld Decoded %p size %d\n",
112               encoded, ret, decoded, decodedLen);
113     buffer_reserve(&vs->input, decodedLen);
114     buffer_append(&vs->input, decoded, decodedLen);
115     return decodedLen;
116 }
117
118
119 static int vnc_auth_sasl_check_access(VncState *vs)
120 {
121     const void *val;
122     int err;
123
124     err = sasl_getprop(vs->sasl.conn, SASL_USERNAME, &val);
125     if (err != SASL_OK) {
126         VNC_DEBUG("cannot query SASL username on connection %d (%s)\n",
127                   err, sasl_errstring(err, NULL, NULL));
128         return -1;
129     }
130     if (val == NULL) {
131         VNC_DEBUG("no client username was found\n");
132         return -1;
133     }
134     VNC_DEBUG("SASL client username %s\n", (const char *)val);
135
136     vs->sasl.username = qemu_strdup((const char*)val);
137
138     return 0;
139 }
140
141 static int vnc_auth_sasl_check_ssf(VncState *vs)
142 {
143     const void *val;
144     int err, ssf;
145
146     if (!vs->sasl.wantSSF)
147         return 1;
148
149     err = sasl_getprop(vs->sasl.conn, SASL_SSF, &val);
150     if (err != SASL_OK)
151         return 0;
152
153     ssf = *(const int *)val;
154     VNC_DEBUG("negotiated an SSF of %d\n", ssf);
155     if (ssf < 56)
156         return 0; /* 56 is good for Kerberos */
157
158     /* Only setup for read initially, because we're about to send an RPC
159      * reply which must be in plain text. When the next incoming RPC
160      * arrives, we'll switch on writes too
161      *
162      * cf qemudClientReadSASL  in qemud.c
163      */
164     vs->sasl.runSSF = 1;
165
166     /* We have a SSF that's good enough */
167     return 1;
168 }
169
170 /*
171  * Step Msg
172  *
173  * Input from client:
174  *
175  * u32 clientin-length
176  * u8-array clientin-string
177  *
178  * Output to client:
179  *
180  * u32 serverout-length
181  * u8-array serverout-strin
182  * u8 continue
183  */
184
185 static int protocol_client_auth_sasl_step_len(VncState *vs, uint8_t *data, size_t len);
186
187 static int protocol_client_auth_sasl_step(VncState *vs, uint8_t *data, size_t len)
188 {
189     uint32_t datalen = len;
190     const char *serverout;
191     unsigned int serveroutlen;
192     int err;
193     char *clientdata = NULL;
194
195     /* NB, distinction of NULL vs "" is *critical* in SASL */
196     if (datalen) {
197         clientdata = (char*)data;
198         clientdata[datalen-1] = '\0'; /* Wire includes '\0', but make sure */
199         datalen--; /* Don't count NULL byte when passing to _start() */
200     }
201
202     VNC_DEBUG("Step using SASL Data %p (%d bytes)\n",
203               clientdata, datalen);
204     err = sasl_server_step(vs->sasl.conn,
205                            clientdata,
206                            datalen,
207                            &serverout,
208                            &serveroutlen);
209     if (err != SASL_OK &&
210         err != SASL_CONTINUE) {
211         VNC_DEBUG("sasl step failed %d (%s)\n",
212                   err, sasl_errdetail(vs->sasl.conn));
213         sasl_dispose(&vs->sasl.conn);
214         vs->sasl.conn = NULL;
215         goto authabort;
216     }
217
218     if (serveroutlen > SASL_DATA_MAX_LEN) {
219         VNC_DEBUG("sasl step reply data too long %d\n",
220                   serveroutlen);
221         sasl_dispose(&vs->sasl.conn);
222         vs->sasl.conn = NULL;
223         goto authabort;
224     }
225
226     VNC_DEBUG("SASL return data %d bytes, nil; %d\n",
227               serveroutlen, serverout ? 0 : 1);
228
229     if (serveroutlen) {
230         vnc_write_u32(vs, serveroutlen + 1);
231         vnc_write(vs, serverout, serveroutlen + 1);
232     } else {
233         vnc_write_u32(vs, 0);
234     }
235
236     /* Whether auth is complete */
237     vnc_write_u8(vs, err == SASL_CONTINUE ? 0 : 1);
238
239     if (err == SASL_CONTINUE) {
240         VNC_DEBUG("%s", "Authentication must continue\n");
241         /* Wait for step length */
242         vnc_read_when(vs, protocol_client_auth_sasl_step_len, 4);
243     } else {
244         if (!vnc_auth_sasl_check_ssf(vs)) {
245             VNC_DEBUG("Authentication rejected for weak SSF %d\n", vs->csock);
246             goto authreject;
247         }
248
249         /* Check username whitelist ACL */
250         if (vnc_auth_sasl_check_access(vs) < 0) {
251             VNC_DEBUG("Authentication rejected for ACL %d\n", vs->csock);
252             goto authreject;
253         }
254
255         VNC_DEBUG("Authentication successful %d\n", vs->csock);
256         vnc_write_u32(vs, 0); /* Accept auth */
257         /*
258          * Delay writing in SSF encoded mode until pending output
259          * buffer is written
260          */
261         if (vs->sasl.runSSF)
262             vs->sasl.waitWriteSSF = vs->output.offset;
263         start_client_init(vs);
264     }
265
266     return 0;
267
268  authreject:
269     vnc_write_u32(vs, 1); /* Reject auth */
270     vnc_write_u32(vs, sizeof("Authentication failed"));
271     vnc_write(vs, "Authentication failed", sizeof("Authentication failed"));
272     vnc_flush(vs);
273     vnc_client_error(vs);
274     return -1;
275
276  authabort:
277     vnc_client_error(vs);
278     return -1;
279 }
280
281 static int protocol_client_auth_sasl_step_len(VncState *vs, uint8_t *data, size_t len)
282 {
283     uint32_t steplen = read_u32(data, 0);
284     VNC_DEBUG("Got client step len %d\n", steplen);
285     if (steplen > SASL_DATA_MAX_LEN) {
286         VNC_DEBUG("Too much SASL data %d\n", steplen);
287         vnc_client_error(vs);
288         return -1;
289     }
290
291     if (steplen == 0)
292         return protocol_client_auth_sasl_step(vs, NULL, 0);
293     else
294         vnc_read_when(vs, protocol_client_auth_sasl_step, steplen);
295     return 0;
296 }
297
298 /*
299  * Start Msg
300  *
301  * Input from client:
302  *
303  * u32 clientin-length
304  * u8-array clientin-string
305  *
306  * Output to client:
307  *
308  * u32 serverout-length
309  * u8-array serverout-strin
310  * u8 continue
311  */
312
313 #define SASL_DATA_MAX_LEN (1024 * 1024)
314
315 static int protocol_client_auth_sasl_start(VncState *vs, uint8_t *data, size_t len)
316 {
317     uint32_t datalen = len;
318     const char *serverout;
319     unsigned int serveroutlen;
320     int err;
321     char *clientdata = NULL;
322
323     /* NB, distinction of NULL vs "" is *critical* in SASL */
324     if (datalen) {
325         clientdata = (char*)data;
326         clientdata[datalen-1] = '\0'; /* Should be on wire, but make sure */
327         datalen--; /* Don't count NULL byte when passing to _start() */
328     }
329
330     VNC_DEBUG("Start SASL auth with mechanism %s. Data %p (%d bytes)\n",
331               vs->sasl.mechlist, clientdata, datalen);
332     err = sasl_server_start(vs->sasl.conn,
333                             vs->sasl.mechlist,
334                             clientdata,
335                             datalen,
336                             &serverout,
337                             &serveroutlen);
338     if (err != SASL_OK &&
339         err != SASL_CONTINUE) {
340         VNC_DEBUG("sasl start failed %d (%s)\n",
341                   err, sasl_errdetail(vs->sasl.conn));
342         sasl_dispose(&vs->sasl.conn);
343         vs->sasl.conn = NULL;
344         goto authabort;
345     }
346     if (serveroutlen > SASL_DATA_MAX_LEN) {
347         VNC_DEBUG("sasl start reply data too long %d\n",
348                   serveroutlen);
349         sasl_dispose(&vs->sasl.conn);
350         vs->sasl.conn = NULL;
351         goto authabort;
352     }
353
354     VNC_DEBUG("SASL return data %d bytes, nil; %d\n",
355               serveroutlen, serverout ? 0 : 1);
356
357     if (serveroutlen) {
358         vnc_write_u32(vs, serveroutlen + 1);
359         vnc_write(vs, serverout, serveroutlen + 1);
360     } else {
361         vnc_write_u32(vs, 0);
362     }
363
364     /* Whether auth is complete */
365     vnc_write_u8(vs, err == SASL_CONTINUE ? 0 : 1);
366
367     if (err == SASL_CONTINUE) {
368         VNC_DEBUG("%s", "Authentication must continue\n");
369         /* Wait for step length */
370         vnc_read_when(vs, protocol_client_auth_sasl_step_len, 4);
371     } else {
372         if (!vnc_auth_sasl_check_ssf(vs)) {
373             VNC_DEBUG("Authentication rejected for weak SSF %d\n", vs->csock);
374             goto authreject;
375         }
376
377         /* Check username whitelist ACL */
378         if (vnc_auth_sasl_check_access(vs) < 0) {
379             VNC_DEBUG("Authentication rejected for ACL %d\n", vs->csock);
380             goto authreject;
381         }
382
383         VNC_DEBUG("Authentication successful %d\n", vs->csock);
384         vnc_write_u32(vs, 0); /* Accept auth */
385         start_client_init(vs);
386     }
387
388     return 0;
389
390  authreject:
391     vnc_write_u32(vs, 1); /* Reject auth */
392     vnc_write_u32(vs, sizeof("Authentication failed"));
393     vnc_write(vs, "Authentication failed", sizeof("Authentication failed"));
394     vnc_flush(vs);
395     vnc_client_error(vs);
396     return -1;
397
398  authabort:
399     vnc_client_error(vs);
400     return -1;
401 }
402
403 static int protocol_client_auth_sasl_start_len(VncState *vs, uint8_t *data, size_t len)
404 {
405     uint32_t startlen = read_u32(data, 0);
406     VNC_DEBUG("Got client start len %d\n", startlen);
407     if (startlen > SASL_DATA_MAX_LEN) {
408         VNC_DEBUG("Too much SASL data %d\n", startlen);
409         vnc_client_error(vs);
410         return -1;
411     }
412
413     if (startlen == 0)
414         return protocol_client_auth_sasl_start(vs, NULL, 0);
415
416     vnc_read_when(vs, protocol_client_auth_sasl_start, startlen);
417     return 0;
418 }
419
420 static int protocol_client_auth_sasl_mechname(VncState *vs, uint8_t *data, size_t len)
421 {
422     char *mechname = malloc(len + 1);
423     if (!mechname) {
424         VNC_DEBUG("Out of memory reading mechname\n");
425         vnc_client_error(vs);
426     }
427     strncpy(mechname, (char*)data, len);
428     mechname[len] = '\0';
429     VNC_DEBUG("Got client mechname '%s' check against '%s'\n",
430               mechname, vs->sasl.mechlist);
431
432     if (strncmp(vs->sasl.mechlist, mechname, len) == 0) {
433         if (vs->sasl.mechlist[len] != '\0' &&
434             vs->sasl.mechlist[len] != ',') {
435             VNC_DEBUG("One %d", vs->sasl.mechlist[len]);
436             vnc_client_error(vs);
437             return -1;
438         }
439     } else {
440         char *offset = strstr(vs->sasl.mechlist, mechname);
441         VNC_DEBUG("Two %p\n", offset);
442         if (!offset) {
443             vnc_client_error(vs);
444             return -1;
445         }
446         VNC_DEBUG("Two '%s'\n", offset);
447         if (offset[-1] != ',' ||
448             (offset[len] != '\0'&&
449              offset[len] != ',')) {
450             vnc_client_error(vs);
451             return -1;
452         }
453     }
454
455     free(vs->sasl.mechlist);
456     vs->sasl.mechlist = mechname;
457
458     VNC_DEBUG("Validated mechname '%s'\n", mechname);
459     vnc_read_when(vs, protocol_client_auth_sasl_start_len, 4);
460     return 0;
461 }
462
463 static int protocol_client_auth_sasl_mechname_len(VncState *vs, uint8_t *data, size_t len)
464 {
465     uint32_t mechlen = read_u32(data, 0);
466     VNC_DEBUG("Got client mechname len %d\n", mechlen);
467     if (mechlen > 100) {
468         VNC_DEBUG("Too long SASL mechname data %d\n", mechlen);
469         vnc_client_error(vs);
470         return -1;
471     }
472     if (mechlen < 1) {
473         VNC_DEBUG("Too short SASL mechname %d\n", mechlen);
474         vnc_client_error(vs);
475         return -1;
476     }
477     vnc_read_when(vs, protocol_client_auth_sasl_mechname,mechlen);
478     return 0;
479 }
480
481 #define USES_X509_AUTH(vs)                            \
482     ((vs)->subauth == VNC_AUTH_VENCRYPT_X509NONE ||   \
483      (vs)->subauth == VNC_AUTH_VENCRYPT_X509VNC ||    \
484      (vs)->subauth == VNC_AUTH_VENCRYPT_X509PLAIN ||  \
485      (vs)->subauth == VNC_AUTH_VENCRYPT_X509SASL)
486
487
488 void start_auth_sasl(VncState *vs)
489 {
490     const char *mechlist = NULL;
491     sasl_security_properties_t secprops;
492     int err;
493     char *localAddr, *remoteAddr;
494     int mechlistlen;
495
496     VNC_DEBUG("Initialize SASL auth %d\n", vs->csock);
497
498     /* Get local & remote client addresses in form  IPADDR;PORT */
499     if (!(localAddr = vnc_socket_local_addr("%s;%s", vs->csock)))
500         goto authabort;
501
502     if (!(remoteAddr = vnc_socket_remote_addr("%s;%s", vs->csock))) {
503         free(localAddr);
504         goto authabort;
505     }
506
507     err = sasl_server_new("vnc",
508                           NULL, /* FQDN - just delegates to gethostname */
509                           NULL, /* User realm */
510                           localAddr,
511                           remoteAddr,
512                           NULL, /* Callbacks, not needed */
513                           SASL_SUCCESS_DATA,
514                           &vs->sasl.conn);
515     free(localAddr);
516     free(remoteAddr);
517     localAddr = remoteAddr = NULL;
518
519     if (err != SASL_OK) {
520         VNC_DEBUG("sasl context setup failed %d (%s)",
521                   err, sasl_errstring(err, NULL, NULL));
522         vs->sasl.conn = NULL;
523         goto authabort;
524     }
525
526 #ifdef CONFIG_VNC_TLS
527     /* Inform SASL that we've got an external SSF layer from TLS/x509 */
528     if (vs->vd->auth == VNC_AUTH_VENCRYPT &&
529         vs->vd->subauth == VNC_AUTH_VENCRYPT_X509SASL) {
530         gnutls_cipher_algorithm_t cipher;
531         sasl_ssf_t ssf;
532
533         cipher = gnutls_cipher_get(vs->tls.session);
534         if (!(ssf = (sasl_ssf_t)gnutls_cipher_get_key_size(cipher))) {
535             VNC_DEBUG("%s", "cannot TLS get cipher size\n");
536             sasl_dispose(&vs->sasl.conn);
537             vs->sasl.conn = NULL;
538             goto authabort;
539         }
540         ssf *= 8; /* tls key size is bytes, sasl wants bits */
541
542         err = sasl_setprop(vs->sasl.conn, SASL_SSF_EXTERNAL, &ssf);
543         if (err != SASL_OK) {
544             VNC_DEBUG("cannot set SASL external SSF %d (%s)\n",
545                       err, sasl_errstring(err, NULL, NULL));
546             sasl_dispose(&vs->sasl.conn);
547             vs->sasl.conn = NULL;
548             goto authabort;
549         }
550     } else
551 #endif /* CONFIG_VNC_TLS */
552         vs->sasl.wantSSF = 1;
553
554     memset (&secprops, 0, sizeof secprops);
555     /* Inform SASL that we've got an external SSF layer from TLS */
556     if (strncmp(vs->vd->display, "unix:", 5) == 0
557 #ifdef CONFIG_VNC_TLS
558         /* Disable SSF, if using TLS+x509+SASL only. TLS without x509
559            is not sufficiently strong */
560         || (vs->vd->auth == VNC_AUTH_VENCRYPT &&
561             vs->vd->subauth == VNC_AUTH_VENCRYPT_X509SASL)
562 #endif /* CONFIG_VNC_TLS */
563         ) {
564         /* If we've got TLS or UNIX domain sock, we don't care about SSF */
565         secprops.min_ssf = 0;
566         secprops.max_ssf = 0;
567         secprops.maxbufsize = 8192;
568         secprops.security_flags = 0;
569     } else {
570         /* Plain TCP, better get an SSF layer */
571         secprops.min_ssf = 56; /* Good enough to require kerberos */
572         secprops.max_ssf = 100000; /* Arbitrary big number */
573         secprops.maxbufsize = 8192;
574         /* Forbid any anonymous or trivially crackable auth */
575         secprops.security_flags =
576             SASL_SEC_NOANONYMOUS | SASL_SEC_NOPLAINTEXT;
577     }
578
579     err = sasl_setprop(vs->sasl.conn, SASL_SEC_PROPS, &secprops);
580     if (err != SASL_OK) {
581         VNC_DEBUG("cannot set SASL security props %d (%s)\n",
582                   err, sasl_errstring(err, NULL, NULL));
583         sasl_dispose(&vs->sasl.conn);
584         vs->sasl.conn = NULL;
585         goto authabort;
586     }
587
588     err = sasl_listmech(vs->sasl.conn,
589                         NULL, /* Don't need to set user */
590                         "", /* Prefix */
591                         ",", /* Separator */
592                         "", /* Suffix */
593                         &mechlist,
594                         NULL,
595                         NULL);
596     if (err != SASL_OK) {
597         VNC_DEBUG("cannot list SASL mechanisms %d (%s)\n",
598                   err, sasl_errdetail(vs->sasl.conn));
599         sasl_dispose(&vs->sasl.conn);
600         vs->sasl.conn = NULL;
601         goto authabort;
602     }
603     VNC_DEBUG("Available mechanisms for client: '%s'\n", mechlist);
604
605     if (!(vs->sasl.mechlist = strdup(mechlist))) {
606         VNC_DEBUG("Out of memory");
607         sasl_dispose(&vs->sasl.conn);
608         vs->sasl.conn = NULL;
609         goto authabort;
610     }
611     mechlistlen = strlen(mechlist);
612     vnc_write_u32(vs, mechlistlen);
613     vnc_write(vs, mechlist, mechlistlen);
614     vnc_flush(vs);
615
616     VNC_DEBUG("Wait for client mechname length\n");
617     vnc_read_when(vs, protocol_client_auth_sasl_mechname_len, 4);
618
619     return;
620
621  authabort:
622     vnc_client_error(vs);
623     return;
624 }
625
626