|
|
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 %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 = qemu_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: vnc_client_error(vs); ! 448: return -1; ! 449: } ! 450: } else { ! 451: char *offset = strstr(vs->sasl.mechlist, mechname); ! 452: VNC_DEBUG("Two %p\n", offset); ! 453: if (!offset) { ! 454: vnc_client_error(vs); ! 455: return -1; ! 456: } ! 457: VNC_DEBUG("Two '%s'\n", offset); ! 458: if (offset[-1] != ',' || ! 459: (offset[len] != '\0'&& ! 460: offset[len] != ',')) { ! 461: vnc_client_error(vs); ! 462: return -1; ! 463: } ! 464: } ! 465: ! 466: free(vs->sasl.mechlist); ! 467: vs->sasl.mechlist = mechname; ! 468: ! 469: VNC_DEBUG("Validated mechname '%s'\n", mechname); ! 470: vnc_read_when(vs, protocol_client_auth_sasl_start_len, 4); ! 471: return 0; ! 472: } ! 473: ! 474: static int protocol_client_auth_sasl_mechname_len(VncState *vs, uint8_t *data, size_t len) ! 475: { ! 476: uint32_t mechlen = read_u32(data, 0); ! 477: VNC_DEBUG("Got client mechname len %d\n", mechlen); ! 478: if (mechlen > 100) { ! 479: VNC_DEBUG("Too long SASL mechname data %d\n", mechlen); ! 480: vnc_client_error(vs); ! 481: return -1; ! 482: } ! 483: if (mechlen < 1) { ! 484: VNC_DEBUG("Too short SASL mechname %d\n", mechlen); ! 485: vnc_client_error(vs); ! 486: return -1; ! 487: } ! 488: vnc_read_when(vs, protocol_client_auth_sasl_mechname,mechlen); ! 489: return 0; ! 490: } ! 491: ! 492: #define USES_X509_AUTH(vs) \ ! 493: ((vs)->subauth == VNC_AUTH_VENCRYPT_X509NONE || \ ! 494: (vs)->subauth == VNC_AUTH_VENCRYPT_X509VNC || \ ! 495: (vs)->subauth == VNC_AUTH_VENCRYPT_X509PLAIN || \ ! 496: (vs)->subauth == VNC_AUTH_VENCRYPT_X509SASL) ! 497: ! 498: ! 499: void start_auth_sasl(VncState *vs) ! 500: { ! 501: const char *mechlist = NULL; ! 502: sasl_security_properties_t secprops; ! 503: int err; ! 504: char *localAddr, *remoteAddr; ! 505: int mechlistlen; ! 506: ! 507: VNC_DEBUG("Initialize SASL auth %d\n", vs->csock); ! 508: ! 509: /* Get local & remote client addresses in form IPADDR;PORT */ ! 510: if (!(localAddr = vnc_socket_local_addr("%s;%s", vs->csock))) ! 511: goto authabort; ! 512: ! 513: if (!(remoteAddr = vnc_socket_remote_addr("%s;%s", vs->csock))) { ! 514: free(localAddr); ! 515: goto authabort; ! 516: } ! 517: ! 518: err = sasl_server_new("vnc", ! 519: NULL, /* FQDN - just delegates to gethostname */ ! 520: NULL, /* User realm */ ! 521: localAddr, ! 522: remoteAddr, ! 523: NULL, /* Callbacks, not needed */ ! 524: SASL_SUCCESS_DATA, ! 525: &vs->sasl.conn); ! 526: free(localAddr); ! 527: free(remoteAddr); ! 528: localAddr = remoteAddr = NULL; ! 529: ! 530: if (err != SASL_OK) { ! 531: VNC_DEBUG("sasl context setup failed %d (%s)", ! 532: err, sasl_errstring(err, NULL, NULL)); ! 533: vs->sasl.conn = NULL; ! 534: goto authabort; ! 535: } ! 536: ! 537: #ifdef CONFIG_VNC_TLS ! 538: /* Inform SASL that we've got an external SSF layer from TLS/x509 */ ! 539: if (vs->vd->auth == VNC_AUTH_VENCRYPT && ! 540: vs->vd->subauth == VNC_AUTH_VENCRYPT_X509SASL) { ! 541: gnutls_cipher_algorithm_t cipher; ! 542: sasl_ssf_t ssf; ! 543: ! 544: cipher = gnutls_cipher_get(vs->tls.session); ! 545: if (!(ssf = (sasl_ssf_t)gnutls_cipher_get_key_size(cipher))) { ! 546: VNC_DEBUG("%s", "cannot TLS get cipher size\n"); ! 547: sasl_dispose(&vs->sasl.conn); ! 548: vs->sasl.conn = NULL; ! 549: goto authabort; ! 550: } ! 551: ssf *= 8; /* tls key size is bytes, sasl wants bits */ ! 552: ! 553: err = sasl_setprop(vs->sasl.conn, SASL_SSF_EXTERNAL, &ssf); ! 554: if (err != SASL_OK) { ! 555: VNC_DEBUG("cannot set SASL external SSF %d (%s)\n", ! 556: err, sasl_errstring(err, NULL, NULL)); ! 557: sasl_dispose(&vs->sasl.conn); ! 558: vs->sasl.conn = NULL; ! 559: goto authabort; ! 560: } ! 561: } else ! 562: #endif /* CONFIG_VNC_TLS */ ! 563: vs->sasl.wantSSF = 1; ! 564: ! 565: memset (&secprops, 0, sizeof secprops); ! 566: /* Inform SASL that we've got an external SSF layer from TLS */ ! 567: if (strncmp(vs->vd->display, "unix:", 5) == 0 ! 568: #ifdef CONFIG_VNC_TLS ! 569: /* Disable SSF, if using TLS+x509+SASL only. TLS without x509 ! 570: is not sufficiently strong */ ! 571: || (vs->vd->auth == VNC_AUTH_VENCRYPT && ! 572: vs->vd->subauth == VNC_AUTH_VENCRYPT_X509SASL) ! 573: #endif /* CONFIG_VNC_TLS */ ! 574: ) { ! 575: /* If we've got TLS or UNIX domain sock, we don't care about SSF */ ! 576: secprops.min_ssf = 0; ! 577: secprops.max_ssf = 0; ! 578: secprops.maxbufsize = 8192; ! 579: secprops.security_flags = 0; ! 580: } else { ! 581: /* Plain TCP, better get an SSF layer */ ! 582: secprops.min_ssf = 56; /* Good enough to require kerberos */ ! 583: secprops.max_ssf = 100000; /* Arbitrary big number */ ! 584: secprops.maxbufsize = 8192; ! 585: /* Forbid any anonymous or trivially crackable auth */ ! 586: secprops.security_flags = ! 587: SASL_SEC_NOANONYMOUS | SASL_SEC_NOPLAINTEXT; ! 588: } ! 589: ! 590: err = sasl_setprop(vs->sasl.conn, SASL_SEC_PROPS, &secprops); ! 591: if (err != SASL_OK) { ! 592: VNC_DEBUG("cannot set SASL security props %d (%s)\n", ! 593: err, sasl_errstring(err, NULL, NULL)); ! 594: sasl_dispose(&vs->sasl.conn); ! 595: vs->sasl.conn = NULL; ! 596: goto authabort; ! 597: } ! 598: ! 599: err = sasl_listmech(vs->sasl.conn, ! 600: NULL, /* Don't need to set user */ ! 601: "", /* Prefix */ ! 602: ",", /* Separator */ ! 603: "", /* Suffix */ ! 604: &mechlist, ! 605: NULL, ! 606: NULL); ! 607: if (err != SASL_OK) { ! 608: VNC_DEBUG("cannot list SASL mechanisms %d (%s)\n", ! 609: err, sasl_errdetail(vs->sasl.conn)); ! 610: sasl_dispose(&vs->sasl.conn); ! 611: vs->sasl.conn = NULL; ! 612: goto authabort; ! 613: } ! 614: VNC_DEBUG("Available mechanisms for client: '%s'\n", mechlist); ! 615: ! 616: if (!(vs->sasl.mechlist = strdup(mechlist))) { ! 617: VNC_DEBUG("Out of memory"); ! 618: sasl_dispose(&vs->sasl.conn); ! 619: vs->sasl.conn = NULL; ! 620: goto authabort; ! 621: } ! 622: mechlistlen = strlen(mechlist); ! 623: vnc_write_u32(vs, mechlistlen); ! 624: vnc_write(vs, mechlist, mechlistlen); ! 625: vnc_flush(vs); ! 626: ! 627: VNC_DEBUG("Wait for client mechname length\n"); ! 628: vnc_read_when(vs, protocol_client_auth_sasl_mechname_len, 4); ! 629: ! 630: return; ! 631: ! 632: authabort: ! 633: vnc_client_error(vs); ! 634: return; ! 635: } ! 636: ! 637:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.