#include "qemu/osdep.h"
#include "qapi/error.h"
+#include "authz/base.h"
#include "vnc.h"
#include "trace.h"
+/*
+ * Apple has deprecated sasl.h functions in OS X 10.11. Therefore,
+ * files that use SASL API need to disable -Wdeprecated-declarations.
+ */
+#ifdef CONFIG_DARWIN
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+#endif
+
/* Max amount of data we send/recv for SASL steps to prevent DOS */
#define SASL_DATA_MAX_LEN (1024 * 1024)
+bool vnc_sasl_server_init(Error **errp)
+{
+ int saslErr = sasl_server_init(NULL, "qemu");
+
+ if (saslErr != SASL_OK) {
+ error_setg(errp, "Failed to initialize SASL auth: %s",
+ sasl_errstring(saslErr, NULL, NULL));
+ return false;
+ }
+ return true;
+}
+
void vnc_sasl_client_cleanup(VncState *vs)
{
if (vs->sasl.conn) {
}
-long vnc_client_write_sasl(VncState *vs)
+size_t vnc_client_write_sasl(VncState *vs)
{
- long ret;
+ size_t ret;
VNC_DEBUG("Write SASL: Pending output %p size %zd offset %zd "
"Encoded: %p size %d offset %d\n",
if (err != SASL_OK)
return vnc_client_io_error(vs, -1, NULL);
+ vs->sasl.encodedRawLength = vs->output.offset;
vs->sasl.encodedOffset = 0;
}
vs->sasl.encodedOffset += ret;
if (vs->sasl.encodedOffset == vs->sasl.encodedLength) {
- vs->output.offset = 0;
+ bool throttled = vs->force_update_offset != 0;
+ size_t offset;
+ if (vs->sasl.encodedRawLength >= vs->force_update_offset) {
+ vs->force_update_offset = 0;
+ } else {
+ vs->force_update_offset -= vs->sasl.encodedRawLength;
+ }
+ if (throttled && vs->force_update_offset == 0) {
+ trace_vnc_client_unthrottle_forced(vs, vs->ioc);
+ }
+ offset = vs->output.offset;
+ buffer_advance(&vs->output, vs->sasl.encodedRawLength);
+ if (offset >= vs->throttle_output_offset &&
+ vs->output.offset < vs->throttle_output_offset) {
+ trace_vnc_client_unthrottle_incremental(vs, vs->ioc,
+ vs->output.offset);
+ }
vs->sasl.encoded = NULL;
vs->sasl.encodedOffset = vs->sasl.encodedLength = 0;
}
g_source_remove(vs->ioc_tag);
}
vs->ioc_tag = qio_channel_add_watch(
- vs->ioc, G_IO_IN, vnc_client_io, vs, NULL);
+ vs->ioc, G_IO_IN | G_IO_HUP | G_IO_ERR,
+ vnc_client_io, vs, NULL);
}
return ret;
}
-long vnc_client_read_sasl(VncState *vs)
+size_t vnc_client_read_sasl(VncState *vs)
{
- long ret;
+ size_t ret;
uint8_t encoded[4096];
const char *decoded;
unsigned int decodedLen;
static int vnc_auth_sasl_check_access(VncState *vs)
{
const void *val;
- int err;
- int allow;
+ int rv;
+ Error *err = NULL;
+ bool allow;
- err = sasl_getprop(vs->sasl.conn, SASL_USERNAME, &val);
- if (err != SASL_OK) {
+ rv = sasl_getprop(vs->sasl.conn, SASL_USERNAME, &val);
+ if (rv != SASL_OK) {
trace_vnc_auth_fail(vs, vs->auth, "Cannot fetch SASL username",
- sasl_errstring(err, NULL, NULL));
+ sasl_errstring(rv, NULL, NULL));
return -1;
}
if (val == NULL) {
vs->sasl.username = g_strdup((const char*)val);
trace_vnc_auth_sasl_username(vs, vs->sasl.username);
- if (vs->vd->sasl.acl == NULL) {
+ if (vs->vd->sasl.authzid == NULL) {
trace_vnc_auth_sasl_acl(vs, 1);
return 0;
}
- allow = qemu_acl_party_is_allowed(vs->vd->sasl.acl, vs->sasl.username);
+ allow = qauthz_is_allowed_by_id(vs->vd->sasl.authzid,
+ vs->sasl.username, &err);
+ if (err) {
+ trace_vnc_auth_fail(vs, vs->auth, "Error from authz",
+ error_get_pretty(err));
+ error_free(err);
+ return -1;
+ }
trace_vnc_auth_sasl_acl(vs, allow);
return allow ? 0 : -1;
goto authreject;
}
- /* Check username whitelist ACL */
+ /* Check the username access control list */
if (vnc_auth_sasl_check_access(vs) < 0) {
goto authreject;
}
goto authreject;
}
- /* Check username whitelist ACL */
+ /* Check the username access control list */
if (vnc_auth_sasl_check_access(vs) < 0) {
goto authreject;
}
if (addr->type != SOCKET_ADDRESS_TYPE_INET) {
error_setg(errp, "Not an inet socket type");
+ qapi_free_SocketAddress(addr);
return NULL;
}
ret = g_strdup_printf("%s;%s", addr->u.inet.host, addr->u.inet.port);
/* 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;
if (keysize < 0) {
trace_vnc_auth_fail(vs, vs->auth, "cannot TLS get cipher size",
error_get_pretty(local_err));
- error_free(local_err);
sasl_dispose(&vs->sasl.conn);
vs->sasl.conn = NULL;
goto authabort;