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