xref: /openbmc/qemu/ui/vnc-auth-sasl.c (revision 753d11f2)
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 %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 = malloc(len + 1);
434     if (!mechname) {
435         VNC_DEBUG("Out of memory reading mechname\n");
436         vnc_client_error(vs);
437     }
438     strncpy(mechname, (char*)data, len);
439     mechname[len] = '\0';
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     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     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 void start_auth_sasl(VncState *vs)
495 {
496     const char *mechlist = NULL;
497     sasl_security_properties_t secprops;
498     int err;
499     char *localAddr, *remoteAddr;
500     int mechlistlen;
501 
502     VNC_DEBUG("Initialize SASL auth %d\n", vs->csock);
503 
504     /* Get local & remote client addresses in form  IPADDR;PORT */
505     if (!(localAddr = vnc_socket_local_addr("%s;%s", vs->csock)))
506         goto authabort;
507 
508     if (!(remoteAddr = vnc_socket_remote_addr("%s;%s", vs->csock))) {
509         free(localAddr);
510         goto authabort;
511     }
512 
513     err = sasl_server_new("vnc",
514                           NULL, /* FQDN - just delegates to gethostname */
515                           NULL, /* User realm */
516                           localAddr,
517                           remoteAddr,
518                           NULL, /* Callbacks, not needed */
519                           SASL_SUCCESS_DATA,
520                           &vs->sasl.conn);
521     free(localAddr);
522     free(remoteAddr);
523     localAddr = remoteAddr = NULL;
524 
525     if (err != SASL_OK) {
526         VNC_DEBUG("sasl context setup failed %d (%s)",
527                   err, sasl_errstring(err, NULL, NULL));
528         vs->sasl.conn = NULL;
529         goto authabort;
530     }
531 
532 #ifdef CONFIG_VNC_TLS
533     /* Inform SASL that we've got an external SSF layer from TLS/x509 */
534     if (vs->auth == VNC_AUTH_VENCRYPT &&
535         vs->subauth == VNC_AUTH_VENCRYPT_X509SASL) {
536         gnutls_cipher_algorithm_t cipher;
537         sasl_ssf_t ssf;
538 
539         cipher = gnutls_cipher_get(vs->tls.session);
540         if (!(ssf = (sasl_ssf_t)gnutls_cipher_get_key_size(cipher))) {
541             VNC_DEBUG("%s", "cannot TLS get cipher size\n");
542             sasl_dispose(&vs->sasl.conn);
543             vs->sasl.conn = NULL;
544             goto authabort;
545         }
546         ssf *= 8; /* tls key size is bytes, sasl wants bits */
547 
548         err = sasl_setprop(vs->sasl.conn, SASL_SSF_EXTERNAL, &ssf);
549         if (err != SASL_OK) {
550             VNC_DEBUG("cannot set SASL external SSF %d (%s)\n",
551                       err, sasl_errstring(err, NULL, NULL));
552             sasl_dispose(&vs->sasl.conn);
553             vs->sasl.conn = NULL;
554             goto authabort;
555         }
556     } else
557 #endif /* CONFIG_VNC_TLS */
558         vs->sasl.wantSSF = 1;
559 
560     memset (&secprops, 0, sizeof secprops);
561     /* Inform SASL that we've got an external SSF layer from TLS */
562     if (strncmp(vs->vd->display, "unix:", 5) == 0
563 #ifdef CONFIG_VNC_TLS
564         /* Disable SSF, if using TLS+x509+SASL only. TLS without x509
565            is not sufficiently strong */
566         || (vs->auth == VNC_AUTH_VENCRYPT &&
567             vs->subauth == VNC_AUTH_VENCRYPT_X509SASL)
568 #endif /* CONFIG_VNC_TLS */
569         ) {
570         /* If we've got TLS or UNIX domain sock, we don't care about SSF */
571         secprops.min_ssf = 0;
572         secprops.max_ssf = 0;
573         secprops.maxbufsize = 8192;
574         secprops.security_flags = 0;
575     } else {
576         /* Plain TCP, better get an SSF layer */
577         secprops.min_ssf = 56; /* Good enough to require kerberos */
578         secprops.max_ssf = 100000; /* Arbitrary big number */
579         secprops.maxbufsize = 8192;
580         /* Forbid any anonymous or trivially crackable auth */
581         secprops.security_flags =
582             SASL_SEC_NOANONYMOUS | SASL_SEC_NOPLAINTEXT;
583     }
584 
585     err = sasl_setprop(vs->sasl.conn, SASL_SEC_PROPS, &secprops);
586     if (err != SASL_OK) {
587         VNC_DEBUG("cannot set SASL security props %d (%s)\n",
588                   err, sasl_errstring(err, NULL, NULL));
589         sasl_dispose(&vs->sasl.conn);
590         vs->sasl.conn = NULL;
591         goto authabort;
592     }
593 
594     err = sasl_listmech(vs->sasl.conn,
595                         NULL, /* Don't need to set user */
596                         "", /* Prefix */
597                         ",", /* Separator */
598                         "", /* Suffix */
599                         &mechlist,
600                         NULL,
601                         NULL);
602     if (err != SASL_OK) {
603         VNC_DEBUG("cannot list SASL mechanisms %d (%s)\n",
604                   err, sasl_errdetail(vs->sasl.conn));
605         sasl_dispose(&vs->sasl.conn);
606         vs->sasl.conn = NULL;
607         goto authabort;
608     }
609     VNC_DEBUG("Available mechanisms for client: '%s'\n", mechlist);
610 
611     if (!(vs->sasl.mechlist = strdup(mechlist))) {
612         VNC_DEBUG("Out of memory");
613         sasl_dispose(&vs->sasl.conn);
614         vs->sasl.conn = NULL;
615         goto authabort;
616     }
617     mechlistlen = strlen(mechlist);
618     vnc_write_u32(vs, mechlistlen);
619     vnc_write(vs, mechlist, mechlistlen);
620     vnc_flush(vs);
621 
622     VNC_DEBUG("Wait for client mechname length\n");
623     vnc_read_when(vs, protocol_client_auth_sasl_mechname_len, 4);
624 
625     return;
626 
627  authabort:
628     vnc_client_error(vs);
629     return;
630 }
631 
632 
633