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