xref: /qemu/ui/vnc-auth-sasl.c (revision 7a4e543d)
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 "qemu/osdep.h"
26 #include "vnc.h"
27 
28 /* Max amount of data we send/recv for SASL steps to prevent DOS */
29 #define SASL_DATA_MAX_LEN (1024 * 1024)
30 
31 
32 void vnc_sasl_client_cleanup(VncState *vs)
33 {
34     if (vs->sasl.conn) {
35         vs->sasl.runSSF = false;
36         vs->sasl.wantSSF = false;
37         vs->sasl.waitWriteSSF = 0;
38         vs->sasl.encodedLength = vs->sasl.encodedOffset = 0;
39         vs->sasl.encoded = NULL;
40         g_free(vs->sasl.username);
41         g_free(vs->sasl.mechlist);
42         vs->sasl.username = vs->sasl.mechlist = NULL;
43         sasl_dispose(&vs->sasl.conn);
44         vs->sasl.conn = NULL;
45     }
46 }
47 
48 
49 long vnc_client_write_sasl(VncState *vs)
50 {
51     long ret;
52 
53     VNC_DEBUG("Write SASL: Pending output %p size %zd offset %zd "
54               "Encoded: %p size %d offset %d\n",
55               vs->output.buffer, vs->output.capacity, vs->output.offset,
56               vs->sasl.encoded, vs->sasl.encodedLength, vs->sasl.encodedOffset);
57 
58     if (!vs->sasl.encoded) {
59         int err;
60         err = sasl_encode(vs->sasl.conn,
61                           (char *)vs->output.buffer,
62                           vs->output.offset,
63                           (const char **)&vs->sasl.encoded,
64                           &vs->sasl.encodedLength);
65         if (err != SASL_OK)
66             return vnc_client_io_error(vs, -1, NULL);
67 
68         vs->sasl.encodedOffset = 0;
69     }
70 
71     ret = vnc_client_write_buf(vs,
72                                vs->sasl.encoded + vs->sasl.encodedOffset,
73                                vs->sasl.encodedLength - vs->sasl.encodedOffset);
74     if (!ret)
75         return 0;
76 
77     vs->sasl.encodedOffset += ret;
78     if (vs->sasl.encodedOffset == vs->sasl.encodedLength) {
79         vs->output.offset = 0;
80         vs->sasl.encoded = NULL;
81         vs->sasl.encodedOffset = vs->sasl.encodedLength = 0;
82     }
83 
84     /* Can't merge this block with one above, because
85      * someone might have written more unencrypted
86      * data in vs->output while we were processing
87      * SASL encoded output
88      */
89     if (vs->output.offset == 0) {
90         if (vs->ioc_tag) {
91             g_source_remove(vs->ioc_tag);
92         }
93         vs->ioc_tag = qio_channel_add_watch(
94             vs->ioc, G_IO_IN, vnc_client_io, vs, NULL);
95     }
96 
97     return ret;
98 }
99 
100 
101 long vnc_client_read_sasl(VncState *vs)
102 {
103     long ret;
104     uint8_t encoded[4096];
105     const char *decoded;
106     unsigned int decodedLen;
107     int err;
108 
109     ret = vnc_client_read_buf(vs, encoded, sizeof(encoded));
110     if (!ret)
111         return 0;
112 
113     err = sasl_decode(vs->sasl.conn,
114                       (char *)encoded, ret,
115                       &decoded, &decodedLen);
116 
117     if (err != SASL_OK)
118         return vnc_client_io_error(vs, -1, NULL);
119     VNC_DEBUG("Read SASL Encoded %p size %ld Decoded %p size %d\n",
120               encoded, ret, decoded, decodedLen);
121     buffer_reserve(&vs->input, decodedLen);
122     buffer_append(&vs->input, decoded, decodedLen);
123     return decodedLen;
124 }
125 
126 
127 static int vnc_auth_sasl_check_access(VncState *vs)
128 {
129     const void *val;
130     int err;
131     int allow;
132 
133     err = sasl_getprop(vs->sasl.conn, SASL_USERNAME, &val);
134     if (err != SASL_OK) {
135         VNC_DEBUG("cannot query SASL username on connection %d (%s), denying access\n",
136                   err, sasl_errstring(err, NULL, NULL));
137         return -1;
138     }
139     if (val == NULL) {
140         VNC_DEBUG("no client username was found, denying access\n");
141         return -1;
142     }
143     VNC_DEBUG("SASL client username %s\n", (const char *)val);
144 
145     vs->sasl.username = g_strdup((const char*)val);
146 
147     if (vs->vd->sasl.acl == NULL) {
148         VNC_DEBUG("no ACL activated, allowing access\n");
149         return 0;
150     }
151 
152     allow = qemu_acl_party_is_allowed(vs->vd->sasl.acl, vs->sasl.username);
153 
154     VNC_DEBUG("SASL client %s %s by ACL\n", vs->sasl.username,
155               allow ? "allowed" : "denied");
156     return allow ? 0 : -1;
157 }
158 
159 static int vnc_auth_sasl_check_ssf(VncState *vs)
160 {
161     const void *val;
162     int err, ssf;
163 
164     if (!vs->sasl.wantSSF)
165         return 1;
166 
167     err = sasl_getprop(vs->sasl.conn, SASL_SSF, &val);
168     if (err != SASL_OK)
169         return 0;
170 
171     ssf = *(const int *)val;
172     VNC_DEBUG("negotiated an SSF of %d\n", ssf);
173     if (ssf < 56)
174         return 0; /* 56 is good for Kerberos */
175 
176     /* Only setup for read initially, because we're about to send an RPC
177      * reply which must be in plain text. When the next incoming RPC
178      * arrives, we'll switch on writes too
179      *
180      * cf qemudClientReadSASL  in qemud.c
181      */
182     vs->sasl.runSSF = 1;
183 
184     /* We have a SSF that's good enough */
185     return 1;
186 }
187 
188 /*
189  * Step Msg
190  *
191  * Input from client:
192  *
193  * u32 clientin-length
194  * u8-array clientin-string
195  *
196  * Output to client:
197  *
198  * u32 serverout-length
199  * u8-array serverout-strin
200  * u8 continue
201  */
202 
203 static int protocol_client_auth_sasl_step_len(VncState *vs, uint8_t *data, size_t len);
204 
205 static int protocol_client_auth_sasl_step(VncState *vs, uint8_t *data, size_t len)
206 {
207     uint32_t datalen = len;
208     const char *serverout;
209     unsigned int serveroutlen;
210     int err;
211     char *clientdata = NULL;
212 
213     /* NB, distinction of NULL vs "" is *critical* in SASL */
214     if (datalen) {
215         clientdata = (char*)data;
216         clientdata[datalen-1] = '\0'; /* Wire includes '\0', but make sure */
217         datalen--; /* Don't count NULL byte when passing to _start() */
218     }
219 
220     VNC_DEBUG("Step using SASL Data %p (%d bytes)\n",
221               clientdata, datalen);
222     err = sasl_server_step(vs->sasl.conn,
223                            clientdata,
224                            datalen,
225                            &serverout,
226                            &serveroutlen);
227     if (err != SASL_OK &&
228         err != SASL_CONTINUE) {
229         VNC_DEBUG("sasl step failed %d (%s)\n",
230                   err, sasl_errdetail(vs->sasl.conn));
231         sasl_dispose(&vs->sasl.conn);
232         vs->sasl.conn = NULL;
233         goto authabort;
234     }
235 
236     if (serveroutlen > SASL_DATA_MAX_LEN) {
237         VNC_DEBUG("sasl step reply data too long %d\n",
238                   serveroutlen);
239         sasl_dispose(&vs->sasl.conn);
240         vs->sasl.conn = NULL;
241         goto authabort;
242     }
243 
244     VNC_DEBUG("SASL return data %d bytes, nil; %d\n",
245               serveroutlen, serverout ? 0 : 1);
246 
247     if (serveroutlen) {
248         vnc_write_u32(vs, serveroutlen + 1);
249         vnc_write(vs, serverout, serveroutlen + 1);
250     } else {
251         vnc_write_u32(vs, 0);
252     }
253 
254     /* Whether auth is complete */
255     vnc_write_u8(vs, err == SASL_CONTINUE ? 0 : 1);
256 
257     if (err == SASL_CONTINUE) {
258         VNC_DEBUG("%s", "Authentication must continue\n");
259         /* Wait for step length */
260         vnc_read_when(vs, protocol_client_auth_sasl_step_len, 4);
261     } else {
262         if (!vnc_auth_sasl_check_ssf(vs)) {
263             VNC_DEBUG("Authentication rejected for weak SSF %p\n", vs->ioc);
264             goto authreject;
265         }
266 
267         /* Check username whitelist ACL */
268         if (vnc_auth_sasl_check_access(vs) < 0) {
269             VNC_DEBUG("Authentication rejected for ACL %p\n", vs->ioc);
270             goto authreject;
271         }
272 
273         VNC_DEBUG("Authentication successful %p\n", vs->ioc);
274         vnc_write_u32(vs, 0); /* Accept auth */
275         /*
276          * Delay writing in SSF encoded mode until pending output
277          * buffer is written
278          */
279         if (vs->sasl.runSSF)
280             vs->sasl.waitWriteSSF = vs->output.offset;
281         start_client_init(vs);
282     }
283 
284     return 0;
285 
286  authreject:
287     vnc_write_u32(vs, 1); /* Reject auth */
288     vnc_write_u32(vs, sizeof("Authentication failed"));
289     vnc_write(vs, "Authentication failed", sizeof("Authentication failed"));
290     vnc_flush(vs);
291     vnc_client_error(vs);
292     return -1;
293 
294  authabort:
295     vnc_client_error(vs);
296     return -1;
297 }
298 
299 static int protocol_client_auth_sasl_step_len(VncState *vs, uint8_t *data, size_t len)
300 {
301     uint32_t steplen = read_u32(data, 0);
302     VNC_DEBUG("Got client step len %d\n", steplen);
303     if (steplen > SASL_DATA_MAX_LEN) {
304         VNC_DEBUG("Too much SASL data %d\n", steplen);
305         vnc_client_error(vs);
306         return -1;
307     }
308 
309     if (steplen == 0)
310         return protocol_client_auth_sasl_step(vs, NULL, 0);
311     else
312         vnc_read_when(vs, protocol_client_auth_sasl_step, steplen);
313     return 0;
314 }
315 
316 /*
317  * Start Msg
318  *
319  * Input from client:
320  *
321  * u32 clientin-length
322  * u8-array clientin-string
323  *
324  * Output to client:
325  *
326  * u32 serverout-length
327  * u8-array serverout-strin
328  * u8 continue
329  */
330 
331 #define SASL_DATA_MAX_LEN (1024 * 1024)
332 
333 static int protocol_client_auth_sasl_start(VncState *vs, uint8_t *data, size_t len)
334 {
335     uint32_t datalen = len;
336     const char *serverout;
337     unsigned int serveroutlen;
338     int err;
339     char *clientdata = NULL;
340 
341     /* NB, distinction of NULL vs "" is *critical* in SASL */
342     if (datalen) {
343         clientdata = (char*)data;
344         clientdata[datalen-1] = '\0'; /* Should be on wire, but make sure */
345         datalen--; /* Don't count NULL byte when passing to _start() */
346     }
347 
348     VNC_DEBUG("Start SASL auth with mechanism %s. Data %p (%d bytes)\n",
349               vs->sasl.mechlist, clientdata, datalen);
350     err = sasl_server_start(vs->sasl.conn,
351                             vs->sasl.mechlist,
352                             clientdata,
353                             datalen,
354                             &serverout,
355                             &serveroutlen);
356     if (err != SASL_OK &&
357         err != SASL_CONTINUE) {
358         VNC_DEBUG("sasl start failed %d (%s)\n",
359                   err, sasl_errdetail(vs->sasl.conn));
360         sasl_dispose(&vs->sasl.conn);
361         vs->sasl.conn = NULL;
362         goto authabort;
363     }
364     if (serveroutlen > SASL_DATA_MAX_LEN) {
365         VNC_DEBUG("sasl start reply data too long %d\n",
366                   serveroutlen);
367         sasl_dispose(&vs->sasl.conn);
368         vs->sasl.conn = NULL;
369         goto authabort;
370     }
371 
372     VNC_DEBUG("SASL return data %d bytes, nil; %d\n",
373               serveroutlen, serverout ? 0 : 1);
374 
375     if (serveroutlen) {
376         vnc_write_u32(vs, serveroutlen + 1);
377         vnc_write(vs, serverout, serveroutlen + 1);
378     } else {
379         vnc_write_u32(vs, 0);
380     }
381 
382     /* Whether auth is complete */
383     vnc_write_u8(vs, err == SASL_CONTINUE ? 0 : 1);
384 
385     if (err == SASL_CONTINUE) {
386         VNC_DEBUG("%s", "Authentication must continue\n");
387         /* Wait for step length */
388         vnc_read_when(vs, protocol_client_auth_sasl_step_len, 4);
389     } else {
390         if (!vnc_auth_sasl_check_ssf(vs)) {
391             VNC_DEBUG("Authentication rejected for weak SSF %p\n", vs->ioc);
392             goto authreject;
393         }
394 
395         /* Check username whitelist ACL */
396         if (vnc_auth_sasl_check_access(vs) < 0) {
397             VNC_DEBUG("Authentication rejected for ACL %p\n", vs->ioc);
398             goto authreject;
399         }
400 
401         VNC_DEBUG("Authentication successful %p\n", vs->ioc);
402         vnc_write_u32(vs, 0); /* Accept auth */
403         start_client_init(vs);
404     }
405 
406     return 0;
407 
408  authreject:
409     vnc_write_u32(vs, 1); /* Reject auth */
410     vnc_write_u32(vs, sizeof("Authentication failed"));
411     vnc_write(vs, "Authentication failed", sizeof("Authentication failed"));
412     vnc_flush(vs);
413     vnc_client_error(vs);
414     return -1;
415 
416  authabort:
417     vnc_client_error(vs);
418     return -1;
419 }
420 
421 static int protocol_client_auth_sasl_start_len(VncState *vs, uint8_t *data, size_t len)
422 {
423     uint32_t startlen = read_u32(data, 0);
424     VNC_DEBUG("Got client start len %d\n", startlen);
425     if (startlen > SASL_DATA_MAX_LEN) {
426         VNC_DEBUG("Too much SASL data %d\n", startlen);
427         vnc_client_error(vs);
428         return -1;
429     }
430 
431     if (startlen == 0)
432         return protocol_client_auth_sasl_start(vs, NULL, 0);
433 
434     vnc_read_when(vs, protocol_client_auth_sasl_start, startlen);
435     return 0;
436 }
437 
438 static int protocol_client_auth_sasl_mechname(VncState *vs, uint8_t *data, size_t len)
439 {
440     char *mechname = g_strndup((const char *) data, len);
441     VNC_DEBUG("Got client mechname '%s' check against '%s'\n",
442               mechname, vs->sasl.mechlist);
443 
444     if (strncmp(vs->sasl.mechlist, mechname, len) == 0) {
445         if (vs->sasl.mechlist[len] != '\0' &&
446             vs->sasl.mechlist[len] != ',') {
447             VNC_DEBUG("One %d", vs->sasl.mechlist[len]);
448             goto fail;
449         }
450     } else {
451         char *offset = strstr(vs->sasl.mechlist, mechname);
452         VNC_DEBUG("Two %p\n", offset);
453         if (!offset) {
454             goto fail;
455         }
456         VNC_DEBUG("Two '%s'\n", offset);
457         if (offset[-1] != ',' ||
458             (offset[len] != '\0'&&
459              offset[len] != ',')) {
460             goto fail;
461         }
462     }
463 
464     g_free(vs->sasl.mechlist);
465     vs->sasl.mechlist = mechname;
466 
467     VNC_DEBUG("Validated mechname '%s'\n", mechname);
468     vnc_read_when(vs, protocol_client_auth_sasl_start_len, 4);
469     return 0;
470 
471  fail:
472     vnc_client_error(vs);
473     g_free(mechname);
474     return -1;
475 }
476 
477 static int protocol_client_auth_sasl_mechname_len(VncState *vs, uint8_t *data, size_t len)
478 {
479     uint32_t mechlen = read_u32(data, 0);
480     VNC_DEBUG("Got client mechname len %d\n", mechlen);
481     if (mechlen > 100) {
482         VNC_DEBUG("Too long SASL mechname data %d\n", mechlen);
483         vnc_client_error(vs);
484         return -1;
485     }
486     if (mechlen < 1) {
487         VNC_DEBUG("Too short SASL mechname %d\n", mechlen);
488         vnc_client_error(vs);
489         return -1;
490     }
491     vnc_read_when(vs, protocol_client_auth_sasl_mechname,mechlen);
492     return 0;
493 }
494 
495 static char *
496 vnc_socket_ip_addr_string(QIOChannelSocket *ioc,
497                           bool local,
498                           Error **errp)
499 {
500     SocketAddress *addr;
501     char *ret;
502 
503     if (local) {
504         addr = qio_channel_socket_get_local_address(ioc, errp);
505     } else {
506         addr = qio_channel_socket_get_remote_address(ioc, errp);
507     }
508     if (!addr) {
509         return NULL;
510     }
511 
512     if (addr->type != SOCKET_ADDRESS_KIND_INET) {
513         error_setg(errp, "Not an inet socket type");
514         return NULL;
515     }
516     ret = g_strdup_printf("%s;%s", addr->u.inet->host, addr->u.inet->port);
517     qapi_free_SocketAddress(addr);
518     return ret;
519 }
520 
521 void start_auth_sasl(VncState *vs)
522 {
523     const char *mechlist = NULL;
524     sasl_security_properties_t secprops;
525     int err;
526     char *localAddr, *remoteAddr;
527     int mechlistlen;
528 
529     VNC_DEBUG("Initialize SASL auth %p\n", vs->ioc);
530 
531     /* Get local & remote client addresses in form  IPADDR;PORT */
532     localAddr = vnc_socket_ip_addr_string(vs->sioc, true, NULL);
533     if (!localAddr) {
534         goto authabort;
535     }
536 
537     remoteAddr = vnc_socket_ip_addr_string(vs->sioc, false, NULL);
538     if (!remoteAddr) {
539         g_free(localAddr);
540         goto authabort;
541     }
542 
543     err = sasl_server_new("vnc",
544                           NULL, /* FQDN - just delegates to gethostname */
545                           NULL, /* User realm */
546                           localAddr,
547                           remoteAddr,
548                           NULL, /* Callbacks, not needed */
549                           SASL_SUCCESS_DATA,
550                           &vs->sasl.conn);
551     g_free(localAddr);
552     g_free(remoteAddr);
553     localAddr = remoteAddr = NULL;
554 
555     if (err != SASL_OK) {
556         VNC_DEBUG("sasl context setup failed %d (%s)",
557                   err, sasl_errstring(err, NULL, NULL));
558         vs->sasl.conn = NULL;
559         goto authabort;
560     }
561 
562     /* Inform SASL that we've got an external SSF layer from TLS/x509 */
563     if (vs->auth == VNC_AUTH_VENCRYPT &&
564         vs->subauth == VNC_AUTH_VENCRYPT_X509SASL) {
565         Error *local_err = NULL;
566         int keysize;
567         sasl_ssf_t ssf;
568 
569         keysize = qcrypto_tls_session_get_key_size(vs->tls,
570                                                    &local_err);
571         if (keysize < 0) {
572             VNC_DEBUG("cannot TLS get cipher size: %s\n",
573                       error_get_pretty(local_err));
574             error_free(local_err);
575             sasl_dispose(&vs->sasl.conn);
576             vs->sasl.conn = NULL;
577             goto authabort;
578         }
579         ssf = keysize * CHAR_BIT; /* tls key size is bytes, sasl wants bits */
580 
581         err = sasl_setprop(vs->sasl.conn, SASL_SSF_EXTERNAL, &ssf);
582         if (err != SASL_OK) {
583             VNC_DEBUG("cannot set SASL external SSF %d (%s)\n",
584                       err, sasl_errstring(err, NULL, NULL));
585             sasl_dispose(&vs->sasl.conn);
586             vs->sasl.conn = NULL;
587             goto authabort;
588         }
589     } else {
590         vs->sasl.wantSSF = 1;
591     }
592 
593     memset (&secprops, 0, sizeof secprops);
594     /* Inform SASL that we've got an external SSF layer from TLS.
595      *
596      * Disable SSF, if using TLS+x509+SASL only. TLS without x509
597      * is not sufficiently strong
598      */
599     if (vs->vd->is_unix ||
600         (vs->auth == VNC_AUTH_VENCRYPT &&
601          vs->subauth == VNC_AUTH_VENCRYPT_X509SASL)) {
602         /* If we've got TLS or UNIX domain sock, we don't care about SSF */
603         secprops.min_ssf = 0;
604         secprops.max_ssf = 0;
605         secprops.maxbufsize = 8192;
606         secprops.security_flags = 0;
607     } else {
608         /* Plain TCP, better get an SSF layer */
609         secprops.min_ssf = 56; /* Good enough to require kerberos */
610         secprops.max_ssf = 100000; /* Arbitrary big number */
611         secprops.maxbufsize = 8192;
612         /* Forbid any anonymous or trivially crackable auth */
613         secprops.security_flags =
614             SASL_SEC_NOANONYMOUS | SASL_SEC_NOPLAINTEXT;
615     }
616 
617     err = sasl_setprop(vs->sasl.conn, SASL_SEC_PROPS, &secprops);
618     if (err != SASL_OK) {
619         VNC_DEBUG("cannot set SASL security props %d (%s)\n",
620                   err, sasl_errstring(err, NULL, NULL));
621         sasl_dispose(&vs->sasl.conn);
622         vs->sasl.conn = NULL;
623         goto authabort;
624     }
625 
626     err = sasl_listmech(vs->sasl.conn,
627                         NULL, /* Don't need to set user */
628                         "", /* Prefix */
629                         ",", /* Separator */
630                         "", /* Suffix */
631                         &mechlist,
632                         NULL,
633                         NULL);
634     if (err != SASL_OK) {
635         VNC_DEBUG("cannot list SASL mechanisms %d (%s)\n",
636                   err, sasl_errdetail(vs->sasl.conn));
637         sasl_dispose(&vs->sasl.conn);
638         vs->sasl.conn = NULL;
639         goto authabort;
640     }
641     VNC_DEBUG("Available mechanisms for client: '%s'\n", mechlist);
642 
643     vs->sasl.mechlist = g_strdup(mechlist);
644     mechlistlen = strlen(mechlist);
645     vnc_write_u32(vs, mechlistlen);
646     vnc_write(vs, mechlist, mechlistlen);
647     vnc_flush(vs);
648 
649     VNC_DEBUG("Wait for client mechname length\n");
650     vnc_read_when(vs, protocol_client_auth_sasl_mechname_len, 4);
651 
652     return;
653 
654  authabort:
655     vnc_client_error(vs);
656 }
657 
658 
659