static int protocol_client_vencrypt_auth(VncState *vs, uint8_t *data, size_t len) { int auth = read_u32(data, 0); if (auth != vs->vd->subauth) { VNC_DEBUG("Rejecting auth %d\n", auth); vnc_write_u8(vs, 0); /* Reject auth */ vnc_flush(vs); vnc_client_error(vs); } else { VNC_DEBUG("Accepting auth %d, setting up TLS for handshake\n", auth); vnc_write_u8(vs, 1); /* Accept auth */ vnc_flush(vs); if (vnc_tls_client_setup(vs, NEED_X509_AUTH(vs)) < 0) { VNC_DEBUG("Failed to setup TLS\n"); return 0; } VNC_DEBUG("Start TLS VeNCrypt handshake process\n"); if (vnc_start_vencrypt_handshake(vs) < 0) { VNC_DEBUG("Failed to start TLS handshake\n"); return 0; } } return 0; }
static int protocol_client_vencrypt_auth(VncState *vs, uint8_t *data, size_t len) { int auth = read_u32(data, 0); trace_vnc_auth_vencrypt_subauth(vs, auth); if (auth != vs->subauth) { trace_vnc_auth_fail(vs, vs->auth, "Unsupported sub-auth version", ""); vnc_write_u8(vs, 0); /* Reject auth */ vnc_flush(vs); vnc_client_error(vs); } else { Error *err = NULL; QIOChannelTLS *tls; vnc_write_u8(vs, 1); /* Accept auth */ vnc_flush(vs); if (vs->ioc_tag) { g_source_remove(vs->ioc_tag); vs->ioc_tag = 0; } tls = qio_channel_tls_new_server( vs->ioc, vs->vd->tlscreds, vs->vd->tlsauthzid, &err); if (!tls) { trace_vnc_auth_fail(vs, vs->auth, "TLS setup failed", error_get_pretty(err)); error_free(err); vnc_client_error(vs); return 0; } qio_channel_set_name(QIO_CHANNEL(tls), "vnc-server-tls"); object_unref(OBJECT(vs->ioc)); vs->ioc = QIO_CHANNEL(tls); trace_vnc_client_io_wrap(vs, vs->ioc, "tls"); vs->tls = qio_channel_tls_get_session(tls); qio_channel_tls_handshake(tls, vnc_tls_handshake_done, vs, NULL, NULL); } return 0; }
static int protocol_client_vencrypt_auth(VncState *vs, uint8_t *data, size_t len) { int auth = read_u32(data, 0); if (auth != vs->subauth) { VNC_DEBUG("Rejecting auth %d\n", auth); vnc_write_u8(vs, 0); /* Reject auth */ vnc_flush(vs); vnc_client_error(vs); } else { Error *err = NULL; QIOChannelTLS *tls; VNC_DEBUG("Accepting auth %d, setting up TLS for handshake\n", auth); vnc_write_u8(vs, 1); /* Accept auth */ vnc_flush(vs); if (vs->ioc_tag) { g_source_remove(vs->ioc_tag); vs->ioc_tag = 0; } tls = qio_channel_tls_new_server( vs->ioc, vs->vd->tlscreds, vs->vd->tlsaclname, &err); if (!tls) { VNC_DEBUG("Failed to setup TLS %s\n", error_get_pretty(err)); error_free(err); vnc_client_error(vs); return 0; } VNC_DEBUG("Start TLS VeNCrypt handshake process\n"); object_unref(OBJECT(vs->ioc)); vs->ioc = QIO_CHANNEL(tls); vs->tls = qio_channel_tls_get_session(tls); qio_channel_tls_handshake(tls, vnc_tls_handshake_done, vs, NULL); } return 0; }
static int protocol_client_vencrypt_init(VncState *vs, uint8_t *data, size_t len) { trace_vnc_auth_vencrypt_version(vs, (int)data[0], (int)data[1]); if (data[0] != 0 || data[1] != 2) { trace_vnc_auth_fail(vs, vs->auth, "Unsupported version", ""); vnc_write_u8(vs, 1); /* Reject version */ vnc_flush(vs); vnc_client_error(vs); } else { vnc_write_u8(vs, 0); /* Accept version */ vnc_write_u8(vs, 1); /* Number of sub-auths */ vnc_write_u32(vs, vs->subauth); /* The supported auth */ vnc_flush(vs); vnc_read_when(vs, protocol_client_vencrypt_auth, 4); } return 0; }
static int protocol_client_vencrypt_init(VncState *vs, uint8_t *data, size_t len) { if (data[0] != 0 || data[1] != 2) { VNC_DEBUG("Unsupported VeNCrypt protocol %d.%d\n", (int)data[0], (int)data[1]); vnc_write_u8(vs, 1); /* Reject version */ vnc_flush(vs); vnc_client_error(vs); } else { VNC_DEBUG("Sending allowed auth %d\n", vs->subauth); vnc_write_u8(vs, 0); /* Accept version */ vnc_write_u8(vs, 1); /* Number of sub-auths */ vnc_write_u32(vs, vs->subauth); /* The supported auth */ vnc_flush(vs); vnc_read_when(vs, protocol_client_vencrypt_auth, 4); } return 0; }
void start_auth_sasl(VncState *vs) { const char *mechlist = NULL; sasl_security_properties_t secprops; int err; char *localAddr, *remoteAddr; int mechlistlen; VNC_DEBUG("Initialize SASL auth %p\n", vs->ioc); /* Get local & remote client addresses in form IPADDR;PORT */ localAddr = vnc_socket_ip_addr_string(vs->sioc, true, NULL); if (!localAddr) { goto authabort; } remoteAddr = vnc_socket_ip_addr_string(vs->sioc, false, NULL); if (!remoteAddr) { g_free(localAddr); goto authabort; } err = sasl_server_new("vnc", NULL, /* FQDN - just delegates to gethostname */ NULL, /* User realm */ localAddr, remoteAddr, NULL, /* Callbacks, not needed */ SASL_SUCCESS_DATA, &vs->sasl.conn); g_free(localAddr); g_free(remoteAddr); localAddr = remoteAddr = NULL; if (err != SASL_OK) { VNC_DEBUG("sasl context setup failed %d (%s)", err, sasl_errstring(err, NULL, NULL)); vs->sasl.conn = NULL; goto authabort; } /* Inform SASL that we've got an external SSF layer from TLS/x509 */ if (vs->auth == VNC_AUTH_VENCRYPT && vs->subauth == VNC_AUTH_VENCRYPT_X509SASL) { Error *local_err = NULL; int keysize; sasl_ssf_t ssf; keysize = qcrypto_tls_session_get_key_size(vs->tls, &local_err); if (keysize < 0) { VNC_DEBUG("cannot TLS get cipher size: %s\n", error_get_pretty(local_err)); error_free(local_err); sasl_dispose(&vs->sasl.conn); vs->sasl.conn = NULL; goto authabort; } ssf = keysize * CHAR_BIT; /* tls key size is bytes, sasl wants bits */ err = sasl_setprop(vs->sasl.conn, SASL_SSF_EXTERNAL, &ssf); if (err != SASL_OK) { VNC_DEBUG("cannot set SASL external SSF %d (%s)\n", err, sasl_errstring(err, NULL, NULL)); sasl_dispose(&vs->sasl.conn); vs->sasl.conn = NULL; goto authabort; } } else { vs->sasl.wantSSF = 1; } memset (&secprops, 0, sizeof secprops); /* Inform SASL that we've got an external SSF layer from TLS. * * Disable SSF, if using TLS+x509+SASL only. TLS without x509 * is not sufficiently strong */ if (vs->vd->is_unix || (vs->auth == VNC_AUTH_VENCRYPT && vs->subauth == VNC_AUTH_VENCRYPT_X509SASL)) { /* If we've got TLS or UNIX domain sock, we don't care about SSF */ secprops.min_ssf = 0; secprops.max_ssf = 0; secprops.maxbufsize = 8192; secprops.security_flags = 0; } else { /* Plain TCP, better get an SSF layer */ secprops.min_ssf = 56; /* Good enough to require kerberos */ secprops.max_ssf = 100000; /* Arbitrary big number */ secprops.maxbufsize = 8192; /* Forbid any anonymous or trivially crackable auth */ secprops.security_flags = SASL_SEC_NOANONYMOUS | SASL_SEC_NOPLAINTEXT; } err = sasl_setprop(vs->sasl.conn, SASL_SEC_PROPS, &secprops); if (err != SASL_OK) { VNC_DEBUG("cannot set SASL security props %d (%s)\n", err, sasl_errstring(err, NULL, NULL)); sasl_dispose(&vs->sasl.conn); vs->sasl.conn = NULL; goto authabort; } err = sasl_listmech(vs->sasl.conn, NULL, /* Don't need to set user */ "", /* Prefix */ ",", /* Separator */ "", /* Suffix */ &mechlist, NULL, NULL); if (err != SASL_OK) { VNC_DEBUG("cannot list SASL mechanisms %d (%s)\n", err, sasl_errdetail(vs->sasl.conn)); sasl_dispose(&vs->sasl.conn); vs->sasl.conn = NULL; goto authabort; } VNC_DEBUG("Available mechanisms for client: '%s'\n", mechlist); vs->sasl.mechlist = g_strdup(mechlist); mechlistlen = strlen(mechlist); vnc_write_u32(vs, mechlistlen); vnc_write(vs, mechlist, mechlistlen); vnc_flush(vs); VNC_DEBUG("Wait for client mechname length\n"); vnc_read_when(vs, protocol_client_auth_sasl_mechname_len, 4); return; authabort: vnc_client_error(vs); }
static int protocol_client_auth_sasl_start(VncState *vs, uint8_t *data, size_t len) { uint32_t datalen = len; const char *serverout; unsigned int serveroutlen; int err; char *clientdata = NULL; /* NB, distinction of NULL vs "" is *critical* in SASL */ if (datalen) { clientdata = (char*)data; clientdata[datalen-1] = '\0'; /* Should be on wire, but make sure */ datalen--; /* Don't count NULL byte when passing to _start() */ } VNC_DEBUG("Start SASL auth with mechanism %s. Data %p (%d bytes)\n", vs->sasl.mechlist, clientdata, datalen); err = sasl_server_start(vs->sasl.conn, vs->sasl.mechlist, clientdata, datalen, &serverout, &serveroutlen); if (err != SASL_OK && err != SASL_CONTINUE) { VNC_DEBUG("sasl start failed %d (%s)\n", err, sasl_errdetail(vs->sasl.conn)); sasl_dispose(&vs->sasl.conn); vs->sasl.conn = NULL; goto authabort; } if (serveroutlen > SASL_DATA_MAX_LEN) { VNC_DEBUG("sasl start reply data too long %d\n", serveroutlen); sasl_dispose(&vs->sasl.conn); vs->sasl.conn = NULL; goto authabort; } VNC_DEBUG("SASL return data %d bytes, nil; %d\n", serveroutlen, serverout ? 0 : 1); if (serveroutlen) { vnc_write_u32(vs, serveroutlen + 1); vnc_write(vs, serverout, serveroutlen + 1); } else { vnc_write_u32(vs, 0); } /* Whether auth is complete */ vnc_write_u8(vs, err == SASL_CONTINUE ? 0 : 1); if (err == SASL_CONTINUE) { VNC_DEBUG("%s", "Authentication must continue\n"); /* Wait for step length */ vnc_read_when(vs, protocol_client_auth_sasl_step_len, 4); } else { if (!vnc_auth_sasl_check_ssf(vs)) { VNC_DEBUG("Authentication rejected for weak SSF %p\n", vs->ioc); goto authreject; } /* Check username whitelist ACL */ if (vnc_auth_sasl_check_access(vs) < 0) { VNC_DEBUG("Authentication rejected for ACL %p\n", vs->ioc); goto authreject; } VNC_DEBUG("Authentication successful %p\n", vs->ioc); vnc_write_u32(vs, 0); /* Accept auth */ start_client_init(vs); } return 0; authreject: vnc_write_u32(vs, 1); /* Reject auth */ vnc_write_u32(vs, sizeof("Authentication failed")); vnc_write(vs, "Authentication failed", sizeof("Authentication failed")); vnc_flush(vs); vnc_client_error(vs); return -1; authabort: vnc_client_error(vs); return -1; }