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