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